triangle_mesh.template.cc
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2021 Matthias Heil and Andrew Hazel
7 // LIC//
8 // LIC// This library is free software; you can redistribute it and/or
9 // LIC// modify it under the terms of the GNU Lesser General Public
10 // LIC// License as published by the Free Software Foundation; either
11 // LIC// version 2.1 of the License, or (at your option) any later version.
12 // LIC//
13 // LIC// This library is distributed in the hope that it will be useful,
14 // LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // LIC// Lesser General Public License for more details.
17 // LIC//
18 // LIC// You should have received a copy of the GNU Lesser General Public
19 // LIC// License along with this library; if not, write to the Free Software
20 // LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // LIC// 02110-1301 USA.
22 // LIC//
23 // LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 // LIC//
25 // LIC//====================================================================
26 #ifndef OOMPH_TRIANGLE_MESH_TEMPLATE_CC
27 #define OOMPH_TRIANGLE_MESH_TEMPLATE_CC
28 
29 #include <iostream>
30 
31 #include "triangle_mesh.template.h"
32 #include "../generic/map_matrix.h"
33 #include "../generic/multi_domain.h"
34 #include "../generic/projection.h"
35 #include "../generic/face_element_as_geometric_object.h"
36 
37 namespace oomph
38 {
39  //======================================================================
40  /// Build with the help of the scaffold mesh coming
41  /// from the triangle mesh generator Triangle.
42  //======================================================================
43  template<class ELEMENT>
45  const bool& use_attributes)
46  {
47  // Mesh can only be built with 2D Telements.
48  MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(2);
49 
50  // Create space for elements
51  unsigned nelem = Tmp_mesh_pt->nelement();
52  Element_pt.resize(nelem);
53 
54  // Create space for nodes
55  unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
56 
57  // Create a map storing the node_id of the mesh used to update the
58  // node position in the update_triangulateio function
59  std::map<Node*, unsigned> old_global_number;
60 
61  // Store the TriangulateIO node id
62  for (unsigned inod = 0; inod < nnode_scaffold; inod++)
63  {
64  Node* old_node_pt = Tmp_mesh_pt->node_pt(inod);
65  old_global_number[old_node_pt] = inod;
66  }
67 
68  // Initialize the old node id vector
69  Oomph_vertex_nodes_id.resize(nnode_scaffold);
70 
71  // Create space for nodes
72  Node_pt.resize(nnode_scaffold, 0);
73 
74  // Set number of boundaries
75  unsigned nbound = Tmp_mesh_pt->nboundary();
76 
77  // Resize the boundary information
78  set_nboundary(nbound);
79  Boundary_element_pt.resize(nbound);
80  Face_index_at_boundary.resize(nbound);
81 
82  // If we have different regions, then resize the region
83  // information
84  if (use_attributes)
85  {
86  Boundary_region_element_pt.resize(nbound);
87  Face_index_region_at_boundary.resize(nbound);
88  }
89 
90  // Loop over elements in scaffold mesh, visit their nodes
91  for (unsigned e = 0; e < nelem; e++)
92  {
93  Element_pt[e] = new ELEMENT;
94  }
95 
96  // Number of nodes per element from the scaffold mesh
97  unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
98 
99  // Setup map to check the (pseudo-)global node number
100  // Nodes whose number is zero haven't been copied across
101  // into the mesh yet.
102  std::map<Node*, unsigned> global_number;
103  unsigned global_count = 0;
104 
105  // Map of Element attribute pairs
106  std::map<double, Vector<FiniteElement*>> element_attribute_map;
107 
108  // If we're using attributes
109  if (use_attributes)
110  {
111  // If we're using attributes then we need attribute 0 which will
112  // be associated with region 0
113  element_attribute_map[0].resize(0);
114  }
115 
116  // Loop over elements in scaffold mesh, visit their nodes
117  for (unsigned e = 0; e < nelem; e++)
118  {
119  // Loop over all nodes in element
120  for (unsigned j = 0; j < nnod_el; j++)
121  {
122  // Pointer to node in the scaffold mesh
123  Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
124 
125  // Get the (pseudo-)global node number in scaffold mesh
126  // (It's zero [=default] if not visited this one yet)
127  unsigned j_global = global_number[scaffold_node_pt];
128 
129  // Haven't done this one yet
130  if (j_global == 0)
131  {
132  // Find and store the node_id in the old nodes map
133  Oomph_vertex_nodes_id[global_count] =
134  old_global_number[scaffold_node_pt];
135 
136  // Get pointer to set of mesh boundaries that this
137  // scaffold node occupies; NULL if the node is not on any boundary
138  std::set<unsigned>* boundaries_pt;
139  scaffold_node_pt->get_boundaries_pt(boundaries_pt);
140 
141  // Storage for the new node
142  Node* new_node_pt = 0;
143 
144  // Is it on boundaries
145  if (boundaries_pt != 0)
146  {
147  // Create new boundary node
148  new_node_pt =
149  finite_element_pt(e)->construct_boundary_node(j, time_stepper_pt);
150 
151  // Add to boundaries
152  for (std::set<unsigned>::iterator it = boundaries_pt->begin();
153  it != boundaries_pt->end();
154  ++it)
155  {
156  add_boundary_node(*it, new_node_pt);
157  }
158  }
159  // Build normal node
160  else
161  {
162  // Create new normal node
163  new_node_pt =
164  finite_element_pt(e)->construct_node(j, time_stepper_pt);
165  }
166 
167  // Give it a number (not necessarily the global node
168  // number in the scaffold mesh -- we just need something
169  // to keep track...)
170  global_count++;
171  global_number[scaffold_node_pt] = global_count;
172 
173  // Copy new node, created using the NEW element's construct_node
174  // function into global storage, using the same global
175  // node number that we've just associated with the
176  // corresponding node in the scaffold mesh
177  Node_pt[global_count - 1] = new_node_pt;
178 
179  // Assign coordinates
180  for (unsigned i = 0; i < finite_element_pt(e)->dim(); i++)
181  {
182  new_node_pt->x(i) = scaffold_node_pt->x(i);
183  }
184  }
185  // This one has already been done: Copy accross
186  else
187  {
188  finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
189  }
190  }
191 
192  // If we're using attributes
193  if (use_attributes)
194  {
195  element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
196  finite_element_pt(e));
197  }
198  }
199 
200  // Now let's construct lists
201  // Find the number of attributes
202  if (use_attributes)
203  {
204  unsigned n_attribute = element_attribute_map.size();
205 
206  // There are n_attribute different regions
207  this->Region_attribute.resize(n_attribute);
208 
209  // Copy the vectors in the map over to our internal storage
210  unsigned count = 0;
211  for (std::map<double, Vector<FiniteElement*>>::iterator it =
212  element_attribute_map.begin();
213  it != element_attribute_map.end();
214  ++it)
215  {
216  this->Region_attribute[count] = it->first;
217  Region_element_pt[static_cast<unsigned>(Region_attribute[count])] =
218  it->second;
219  ++count;
220  }
221  }
222 
223  // At this point we've created all the elements and
224  // created their vertex nodes. Now we need to create
225  // the additional (midside and internal) nodes!
226 
227  unsigned boundary_id = 0;
228 
229  // Get number of nodes along element edge and dimension of element (2)
230  // from first element
231  unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
232  unsigned dim = finite_element_pt(0)->dim();
233 
234  // Storage for the local coordinate of the new node
235  Vector<double> s(dim);
236 
237  // Get number of nodes in the element from first element
238  unsigned n_node = finite_element_pt(0)->nnode();
239 
240  // Storage for each global edge of the mesh
241  unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
242  Vector<Vector<Node*>> nodes_on_global_edge(n_global_edge);
243 
244  // Loop over elements
245  for (unsigned e = 0; e < nelem; e++)
246  {
247  // Cache pointers to the elements
248  FiniteElement* const elem_pt = finite_element_pt(e);
249  FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
250 
251  // The number of edge nodes is 3*(nnode_1d-1)
252  unsigned n_edge_node = 3 * (n_node_1d - 1);
253 
254  // If there are any more nodes, these are internal and can be
255  // constructed and added directly to the mesh
256  for (unsigned n = n_edge_node; n < n_node; ++n)
257  {
258  // Create new node (it can never be a boundary node)
259  Node* new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
260 
261  // What are the node's local coordinates?
262  elem_pt->local_coordinate_of_node(n, s);
263 
264  // Find the coordinates of the new node from the existing
265  // and fully-functional element in the scaffold mesh
266  for (unsigned i = 0; i < dim; i++)
267  {
268  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
269  }
270 
271  // Add the node to the mesh's global look-up scheme
272  Node_pt.push_back(new_node_pt);
273  }
274 
275  // Now loop over the mid-side edge nodes
276  // Start from node number 3
277  unsigned n = 3;
278 
279  // Loop over edges
280  for (unsigned j = 0; j < 3; j++)
281  {
282  // Find the boundary id of the edge
283  boundary_id = Tmp_mesh_pt->edge_boundary(e, j);
284 
285  // Find the global edge index
286  unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
287 
288  // If the nodes on the edge have not been allocated, construct them
289  if (nodes_on_global_edge[edge_index].size() == 0)
290  {
291  // Loop over the nodes on the edge excluding the ends
292  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
293  {
294  // Storage for the new node
295  Node* new_node_pt = 0;
296 
297  // If the edge is on a boundary, construct a boundary node
298  if (boundary_id > 0)
299  {
300  new_node_pt =
301  elem_pt->construct_boundary_node(n, time_stepper_pt);
302  // Add it to the boundary
303  this->add_boundary_node(boundary_id - 1, new_node_pt);
304  }
305  // Otherwise construct a normal node
306  else
307  {
308  new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
309  }
310 
311  // What are the node's local coordinates?
312  elem_pt->local_coordinate_of_node(n, s);
313 
314  // Find the coordinates of the new node from the existing
315  // and fully-functional element in the scaffold mesh
316  for (unsigned i = 0; i < dim; i++)
317  {
318  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
319  }
320 
321  // Add to the global node list
322  Node_pt.push_back(new_node_pt);
323 
324  // Add to the edge index
325  nodes_on_global_edge[edge_index].push_back(new_node_pt);
326  // Increment the node number
327  ++n;
328  }
329  }
330  // Otherwise just set the pointers
331  // using the fact that the next time the edge is visited
332  // the nodes must be arranged in the other order because all
333  // triangles have the same orientation
334  else
335  {
336  // Loop over the nodes on the edge excluding the ends
337  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
338  {
339  // Set the local node from the edge but indexed the other
340  // way around
341  elem_pt->node_pt(n) =
342  nodes_on_global_edge[edge_index][n_node_1d - 3 - j2];
343  ++n;
344  }
345  }
346 
347  // Set the elements adjacent to the boundary from the
348  // boundary id information
349  if (boundary_id > 0)
350  {
351  Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
352  // Need to put a shift in here because of an inconsistent naming
353  // convention between triangle and face elements
354  Face_index_at_boundary[boundary_id - 1].push_back((j + 2) % 3);
355 
356  // If using regions set up the boundary information
357  if (use_attributes)
358  {
359  unsigned tmp_region =
360  static_cast<unsigned>(Tmp_mesh_pt->element_attribute(e));
361  // Element adjacent to boundary
362  Boundary_region_element_pt[boundary_id - 1][tmp_region].push_back(
363  elem_pt);
364  // Need to put a shift in here because of an inconsistent naming
365  // convention between triangle and face elements
366  Face_index_region_at_boundary[boundary_id - 1][tmp_region]
367  .push_back((j + 2) % 3);
368  }
369  }
370 
371  } // end of loop over edges
372  } // end of loop over elements
373 
374 
375  // Lookup scheme has now been setup
376  Lookup_for_elements_next_boundary_is_setup = true;
377  }
378 
379 #ifdef OOMPH_HAS_MPI
380 
381  //======================================================================
382  /// \short Identify the segments from the old mesh (original mesh)
383  /// in the new mesh (this) and assign initial and final boundary
384  /// coordinates for the segments that create the boundary
385  //======================================================================
386  template<class ELEMENT>
389  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt)
390  {
391  // ------------------------------------------------------------------
392  // First: Get the face elements associated with the current boundary
393  // (nonhalo elements only)
394  // ------------------------------------------------------------------
395  // Temporary storage for face elements
396  Vector<FiniteElement*> face_el_pt;
397 
398  // Temporary storage for number of elements adjacent to the boundary
399  unsigned nele = 0;
400 
401  // Temporary storage for elements adjacent to the boundary that have
402  // a common edge (related with internal boundaries)
403  unsigned n_repeated_ele = 0;
404 
405  const unsigned n_regions = this->nregion();
406 
407  // map to associate the face element to the bulk element, necessary
408  // to attach halo face elements at both sides of each found segment
409  std::map<FiniteElement*, FiniteElement*> face_to_bulk_element_pt;
410 
411  // Temporary storage for already done nodes
412  Vector<std::pair<Node*, Node*>> done_nodes_pt;
413 
414  // If there is more than one region then only use boundary
415  // coordinates from the bulk side (region 0)
416  if (n_regions > 1)
417  {
418  for (unsigned rr = 0; rr < n_regions; rr++)
419  {
420  const unsigned region_id =
421  static_cast<unsigned>(this->Region_attribute[rr]);
422 
423  // Loop over all elements on boundaries in region i_r
424  const unsigned nel_in_region =
425  this->nboundary_element_in_region(b, region_id);
426 
427  unsigned nel_repetead_in_region = 0;
428 
429  // Only bother to do anything else, if there are elements
430  // associated with the boundary and the current region
431  if (nel_in_region > 0)
432  {
433  // Flag that activates when a repeated face element is found,
434  // possibly because we are dealing with an internal boundary
435  bool repeated = false;
436 
437  // Loop over the bulk elements adjacent to boundary b
438  for (unsigned e = 0; e < nel_in_region; e++)
439  {
440  // Get pointer to the bulk element that is adjacent to boundary b
441  FiniteElement* bulk_elem_pt =
442  this->boundary_element_in_region_pt(b, region_id, e);
443 
444 #ifdef OOMPH_HAS_MPI
445  // In a distributed mesh only work with nonhalo elements
446  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
447  {
448  // Increase the number of repeated elements
449  n_repeated_ele++;
450  // Go for the next element
451  continue;
452  }
453 #endif
454 
455  // Find the index of the face of element e along boundary b
456  int face_index =
457  this->face_index_at_boundary_in_region(b, region_id, e);
458 
459  // Before adding the new element we need to be sure that
460  // the edge that this element represent has not been
461  // already added
462  FiniteElement* tmp_ele_pt =
463  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
464 
465  const unsigned n_nodes = tmp_ele_pt->nnode();
466 
467  std::pair<Node*, Node*> tmp_pair = std::make_pair(
468  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
469 
470  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
471  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
472 
473  // Search for repeated nodes
474  const unsigned n_done_nodes = done_nodes_pt.size();
475  for (unsigned l = 0; l < n_done_nodes; l++)
476  {
477  if (tmp_pair == done_nodes_pt[l] ||
478  tmp_pair_inverse == done_nodes_pt[l])
479  {
480  nel_repetead_in_region++;
481  repeated = true;
482  break;
483  }
484  }
485 
486  // Create new face element
487  if (!repeated)
488  {
489  // Add the pair of nodes (edge) to the node dones
490  done_nodes_pt.push_back(tmp_pair);
491  // Create the map to know if the element is halo
492  face_el_pt.push_back(tmp_ele_pt);
493  // Add the element to the face elements
494  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
495  }
496  else
497  {
498  // Clean up
499  delete tmp_ele_pt;
500  tmp_ele_pt = 0;
501  }
502 
503  // Re-start
504  repeated = false;
505 
506  } // for (e < nel_in_region)
507 
508  nele += nel_in_region;
509 
510  n_repeated_ele += nel_repetead_in_region;
511 
512  } // if (nel_in_region > 0)
513  } // for (rr < n_regions)
514  } // if (n_regions > 1)
515  // Otherwise it's just the normal boundary functions
516  else
517  {
518  // Loop over all elements on boundaries
519  nele = this->nboundary_element(b);
520 
521  // Only bother to do anything else, if there are elements
522  if (nele > 0)
523  {
524  // Flag that activates when a repeated face element is found,
525  // possibly because we are dealing with an internal boundary
526  bool repeated = false;
527 
528  // Loop over the bulk elements adjacent to boundary b
529  for (unsigned e = 0; e < nele; e++)
530  {
531  // Get pointer to the bulk element that is adjacent to boundary b
532  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
533 
534 #ifdef OOMPH_HAS_MPI
535  // In a distributed mesh only work with nonhalo elements
536  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
537  {
538  // Increase the number of repeated elements
539  n_repeated_ele++;
540  // Go for the next element
541  continue;
542  }
543 #endif
544 
545  // Find the index of the face of element e along boundary b
546  int face_index = this->face_index_at_boundary(b, e);
547 
548  // Before adding the new element we need to be sure that
549  // the edge that this element represents has not been
550  // already added (only applies for internal boundaries)
551  FiniteElement* tmp_ele_pt =
552  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
553 
554  const unsigned n_nodes = tmp_ele_pt->nnode();
555 
556  std::pair<Node*, Node*> tmp_pair = std::make_pair(
557  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
558 
559  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
560  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
561 
562  // Search for repeated nodes
563  const unsigned n_done_nodes = done_nodes_pt.size();
564  for (unsigned l = 0; l < n_done_nodes; l++)
565  {
566  if (tmp_pair == done_nodes_pt[l] ||
567  tmp_pair_inverse == done_nodes_pt[l])
568  {
569  // Increase the number of repeated elements
570  n_repeated_ele++;
571  // Mark the element as repeated
572  repeated = true;
573  break;
574  }
575  }
576 
577  // Create new face element
578  if (!repeated)
579  {
580  // Add the pair of nodes (edge) to the node dones
581  done_nodes_pt.push_back(tmp_pair);
582  // Add the element to the face elements
583  face_el_pt.push_back(tmp_ele_pt);
584  // Create the map to know if the element is halo
585  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
586  }
587  else
588  {
589  // Free the repeated bulk element!!
590  delete tmp_ele_pt;
591  tmp_ele_pt = 0;
592  }
593 
594  // Re-start
595  repeated = false;
596 
597  } // for (e < nel)
598  } // if (nel > 0)
599 
600  } // else (n_regions > 1)
601 
602  // Do not consider the repeated elements
603  nele -= n_repeated_ele;
604 
605 #ifdef PARANOID
606  if (nele != face_el_pt.size())
607  {
608  std::ostringstream error_message;
609  error_message
610  << "The independent counting of face elements (" << nele << ") for "
611  << "boundary (" << b << ") is different\n"
612  << "from the real number of face elements in the container ("
613  << face_el_pt.size() << ")\n";
614  throw OomphLibError(error_message.str(),
615  "TriangleMesh::identify_boundary_segments_and_assign_"
616  "initial_zeta_values()",
617  OOMPH_EXCEPTION_LOCATION);
618  }
619 #endif
620 
621  // Continue even thought there are no elements, the processor needs
622  // to participate in the communications
623 
624  // ----------------------------------------------------------------
625  // Second: Sort the face elements, only consider nonhalo elements
626  // ----------------------------------------------------------------
627 
628  // A flag vector to mark those face elements that are considered as
629  // halo in the current processor
630  std::vector<bool> is_halo_face_element(nele, false);
631 
632  // Count the total number of non halo face elements
633  unsigned nnon_halo_face_elements = 0;
634 
635  // We will have halo face elements if the mesh is distributed
636  for (unsigned ie = 0; ie < nele; ie++)
637  {
638  // Get the face element
639  FiniteElement* face_ele_pt = face_el_pt[ie];
640  // Get the bulk element
641  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
642  // Check if the bulk element is halo
643  if (!tmp_bulk_ele_pt->is_halo())
644  {
645  is_halo_face_element[ie] = false;
646  nnon_halo_face_elements++;
647  }
648  else
649  {
650  // Mark the face element as halo
651  is_halo_face_element[ie] = true;
652  }
653  } // for (ie < nele)
654 
655 #ifdef PARANOID
656  // Get the total number of halo face elements
657  const unsigned nhalo_face_element = nele - nnon_halo_face_elements;
658  if (nhalo_face_element > 0)
659  {
660  std::ostringstream error_message;
661  error_message
662  << "There should not be halo face elements since they were not "
663  << "considered when computing the face elements\n\n"
664  << "The number of found halo face elements is: " << nhalo_face_element
665  << "\n\n";
666  throw OomphLibError(error_message.str(),
667  "TriangleMesh::identify_boundary_segments_and_assign_"
668  "initial_zeta_values()",
669  OOMPH_EXCEPTION_LOCATION);
670  }
671 #endif
672 
673  // The vector of list to store the "segments" that compound the
674  // boundary (segments may appear only in a distributed mesh)
675  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
676 
677  // Number of already sorted face elements (only nonhalo elements for
678  // a distributed mesh)
679  unsigned nsorted_face_elements = 0;
680 
681  // Keep track of who's done (this apply to nonhalo only, remember we
682  // are only working with nonhalo elements)
683  std::map<FiniteElement*, bool> done_el;
684 
685  // Keep track of which element is inverted (in distributed mesh the
686  // elements may be inverted with respect to the segment they belong)
687  std::map<FiniteElement*, bool> is_inverted;
688 
689  // Iterate until all possible segments have been created
690  while (nsorted_face_elements < nnon_halo_face_elements)
691  {
692  // The ordered list of face elements (in a distributed mesh a
693  // collection of contiguous face elements define a segment)
694  std::list<FiniteElement*> sorted_el_pt;
695  sorted_el_pt.clear();
696 
697 #ifdef PARANOID
698  // Select an initial element for the segment
699  bool found_initial_face_element = false;
700 #endif
701 
702  FiniteElement* ele_face_pt = 0;
703 
704  unsigned iface = 0;
705  for (iface = 0; iface < nele; iface++)
706  {
707  if (!is_halo_face_element[iface])
708  {
709  ele_face_pt = face_el_pt[iface];
710  // If not done then take it as initial face element
711  if (!done_el[ele_face_pt])
712  {
713 #ifdef PARANOID
714  found_initial_face_element = true;
715 #endif
716  nsorted_face_elements++;
717  iface++; // The next element number
718  sorted_el_pt.push_back(ele_face_pt);
719  // Mark as done
720  done_el[ele_face_pt] = true;
721  break;
722  }
723  }
724  } // for (iface < nele)
725 
726 #ifdef PARANOID
727  if (!found_initial_face_element)
728  {
729  std::ostringstream error_message;
730  error_message
731  << "Could not find an initial face element for the current segment\n";
732  throw OomphLibError(error_message.str(),
733  "TriangleMesh::identify_boundary_segments_and_"
734  "assign_initial_zeta_values()",
735  OOMPH_EXCEPTION_LOCATION);
736  }
737 #endif
738 
739  // Number of nodes
740  const unsigned nnod = ele_face_pt->nnode();
741 
742  // Left and right most nodes (the left and right nodes of the
743  // current face element)
744  Node* left_node_pt = ele_face_pt->node_pt(0);
745  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
746 
747  // Continue iterating if a new face element has been added to the
748  // list
749  bool face_element_added = false;
750 
751  // While a new face element has been added to the set of sorted
752  // face elements then re-iterate
753  do
754  {
755  // Start from the next face element since we have already added
756  // the previous one as the initial face element (any previous
757  // face element had to be added on previous iterations)
758  for (unsigned iiface = iface; iiface < nele; iiface++)
759  {
760  // Re-start flag
761  face_element_added = false;
762 
763  // Get the candidate element
764  ele_face_pt = face_el_pt[iiface];
765 
766  // Check that the candidate element has not been done and is
767  // not a halo element
768  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
769  {
770  // Get the left and right nodes of the current element
771  Node* local_left_node_pt = ele_face_pt->node_pt(0);
772  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
773  // New element fits at the left of segment and is not inverted
774  if (left_node_pt == local_right_node_pt)
775  {
776  left_node_pt = local_left_node_pt;
777  sorted_el_pt.push_front(ele_face_pt);
778  is_inverted[ele_face_pt] = false;
779  face_element_added = true;
780  }
781  // New element fits at the left of segment and is inverted
782  else if (left_node_pt == local_left_node_pt)
783  {
784  left_node_pt = local_right_node_pt;
785  sorted_el_pt.push_front(ele_face_pt);
786  is_inverted[ele_face_pt] = true;
787  face_element_added = true;
788  }
789  // New element fits on the right of segment and is not inverted
790  else if (right_node_pt == local_left_node_pt)
791  {
792  right_node_pt = local_right_node_pt;
793  sorted_el_pt.push_back(ele_face_pt);
794  is_inverted[ele_face_pt] = false;
795  face_element_added = true;
796  }
797  // New element fits on the right of segment and is inverted
798  else if (right_node_pt == local_right_node_pt)
799  {
800  right_node_pt = local_left_node_pt;
801  sorted_el_pt.push_back(ele_face_pt);
802  is_inverted[ele_face_pt] = true;
803  face_element_added = true;
804  }
805 
806  if (face_element_added)
807  {
808  done_el[ele_face_pt] = true;
809  nsorted_face_elements++;
810  break;
811  }
812 
813  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
814  } // for (iiface<nnon_halo_face_element)
815  } while (face_element_added &&
816  (nsorted_face_elements < nnon_halo_face_elements));
817 
818  // Store the created segment in the vector of segments
819  segment_sorted_ele_pt.push_back(sorted_el_pt);
820 
821  } // while(nsorted_face_elements < nnon_halo_face_elements);
822 
823  // The number of segments in this processor
824  const unsigned nsegments = segment_sorted_ele_pt.size();
825 
826  // ------------------------------------------------------------------
827  // Third: We have the face elements sorted (nonhalo only), now
828  // assign boundary coordinates to the nodes in the segments. This is
829  // the LOCAL boundary coordinate which is required if the zeta
830  // values need to be inverted
831  // ------------------------------------------------------------------
832  // Necessary in case boundaries with no geom object associated need
833  // to be inverted the zeta values (It is necessary to compute the
834  // arclength but also to store the nodes in a container (set))
835  // ------------------------------------------------------------------
836 
837  // Vector of sets that stores the nodes of each segment based on a
838  // lexicographically order starting from the bottom left node of
839  // each segment
840  Vector<std::set<Node*>> segment_all_nodes_pt;
841 
842  // The arclength of each segment in the current processor
843  Vector<double> segment_arclength(nsegments);
844 
845  // The number of vertices of each segment
846  Vector<unsigned> nvertices_per_segment(nsegments);
847 
848  // The initial zeta for the segment
849  Vector<double> initial_zeta_segment(nsegments);
850 
851  // The final zeta for the segment
852  Vector<double> final_zeta_segment(nsegments);
853 
854 #ifdef PARANOID
855  if (nnon_halo_face_elements > 0 && nsegments == 0)
856  {
857  std::ostringstream error_message;
858  error_message
859  << "The number of segments is zero, but the number of nonhalo\n"
860  << "elements is: (" << nnon_halo_face_elements << ")\n";
861  throw OomphLibError(error_message.str(),
862  "TriangleMesh::identify_boundary_segments_and_assign_"
863  "initial_zeta_values()",
864  OOMPH_EXCEPTION_LOCATION);
865  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
866 #endif
867 
868  // Go through all the segments and compute the LOCAL boundary
869  // coordinates
870  for (unsigned is = 0; is < nsegments; is++)
871  {
872 #ifdef PARANOID
873  if (segment_sorted_ele_pt[is].size() == 0)
874  {
875  std::ostringstream error_message;
876  error_message << "The (" << is << ")-th segment has no elements\n";
877  throw OomphLibError(error_message.str(),
878  "TriangleMesh::identify_boundary_segments_and_"
879  "assign_initial_zeta_values()",
880  OOMPH_EXCEPTION_LOCATION);
881  } // if (segment_sorted_ele_pt[is].size() == 0)
882 #endif
883 
884  // Get access to the first element on the segment
885  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
886 
887  // Number of nodes
888  const unsigned nnod = first_ele_pt->nnode();
889 
890  // Get the first node of the current segment
891  Node* first_node_pt = first_ele_pt->node_pt(0);
892  if (is_inverted[first_ele_pt])
893  {
894  first_node_pt = first_ele_pt->node_pt(nnod - 1);
895  }
896 
897  // Get access to the last element on the segment
898  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
899 
900  // Get the last node of the current segment
901  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
902  if (is_inverted[last_ele_pt])
903  {
904  last_node_pt = last_ele_pt->node_pt(0);
905  }
906 
907  // Coordinates of left node
908  double x_left = first_node_pt->x(0);
909  double y_left = first_node_pt->x(1);
910 
911  // Initialise boundary coordinate (local boundary coordinate for
912  // boundaries with more than one segment)
913  Vector<double> zeta(1, 0.0);
914 
915  // If the boundary has an associated GeomObject then it is not
916  // necessary to compute the arclength, only read the values from
917  // the nodes at the edges
918  if (this->boundary_geom_object_pt(b) != 0)
919  {
920  first_node_pt->get_coordinates_on_boundary(b, zeta);
921  initial_zeta_segment[is] = zeta[0];
922  last_node_pt->get_coordinates_on_boundary(b, zeta);
923  final_zeta_segment[is] = zeta[0];
924  }
925 
926  // Lexicographically bottom left node
927  std::set<Node*> local_nodes_pt;
928  local_nodes_pt.insert(first_node_pt);
929 
930  // Now loop over nodes in order
931  for (std::list<FiniteElement*>::iterator it =
932  segment_sorted_ele_pt[is].begin();
933  it != segment_sorted_ele_pt[is].end();
934  it++)
935  {
936  // Get element
937  FiniteElement* el_pt = *it;
938 
939  // Start node and increment
940  unsigned k_nod = 1;
941  int nod_diff = 1;
942  if (is_inverted[el_pt])
943  {
944  k_nod = nnod - 2;
945  nod_diff = -1;
946  }
947 
948  // Loop over nodes
949  for (unsigned j = 1; j < nnod; j++)
950  {
951  Node* nod_pt = el_pt->node_pt(k_nod);
952  k_nod += nod_diff;
953 
954  // Coordinates of right node
955  double x_right = nod_pt->x(0);
956  double y_right = nod_pt->x(1);
957 
958  // Increment boundary coordinate (the arclength)
959  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
960  (y_right - y_left) * (y_right - y_left));
961 
962  // // When we have a GeomObject associated to the boundary we already
963  // // know the zeta values for the nodes, there is no need to compute
964  // // the arclength
965  // if (this->boundary_geom_object_pt(b)==0)
966  // {
967  // // Set boundary coordinate
968  // nod_pt->set_coordinates_on_boundary(b, zeta);
969  // }
970 
971  // Increment reference coordinate
972  x_left = x_right;
973  y_left = y_right;
974 
975  // Get lexicographically bottom left node but only
976  // use vertex nodes as candidates
977  local_nodes_pt.insert(nod_pt);
978  } // for (j < nnod)
979 
980  } // iterator over the elements in the segment
981 
982  // Store the arclength of the segment
983  segment_arclength[is] = zeta[0];
984 
985  // Store the number of vertices in the segment
986  nvertices_per_segment[is] = local_nodes_pt.size();
987 
988  // Add the nodes for the corresponding segment in the container
989  segment_all_nodes_pt.push_back(local_nodes_pt);
990 
991  } // for (is < nsegments)
992 
993  // Get the number of sets for nodes
994 #ifdef PARANOID
995  if (segment_all_nodes_pt.size() != nsegments)
996  {
997  std::ostringstream error_message;
998  error_message << "The number of segments (" << nsegments
999  << ") and the number of "
1000  << "sets of nodes (" << segment_all_nodes_pt.size()
1001  << ") representing\n"
1002  << "the\nsegments is different!!!\n\n";
1003  throw OomphLibError(
1004  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1005  }
1006 #endif
1007 
1008  // Store the initial arclength for each segment of boundary in the
1009  // current processor, initalise to zero in case we have a non
1010  // distributed boundary
1011  Vector<double> initial_segment_arclength(nsegments, 0.0);
1012 
1013  // Associated the index of the current segment to the segment index
1014  // in the original mesh (input mesh)
1015  Vector<unsigned> current_segment_to_original_segment_index(nsegments);
1016 
1017  // Each segment needs to know whether it has to be inverted or not
1018  // Store whether a segment needs to be inverted or not
1019  Vector<unsigned> segment_inverted(nsegments);
1020 
1021  // -----------------------------------------------------------------
1022  // Fourth: Identify the segments with the ones in the original mesh
1023  // (has sense only in the adaptation process)
1024  // -----------------------------------------------------------------
1025 
1026  // Now check if there are segments associated to this boundary
1027  if (nsegments > 0)
1028  {
1029 #ifdef PARANOID
1030  // Double check that the same number of coordinates (nsegments)
1031  // have been established for the boundary
1032  const unsigned nsegments_initial_coordinates =
1033  original_mesh_pt->boundary_segment_initial_coordinate(b).size();
1034 
1035  const unsigned nsegments_final_coordinates =
1036  original_mesh_pt->boundary_segment_final_coordinate(b).size();
1037 
1038  if (nsegments_initial_coordinates != nsegments_final_coordinates)
1039  {
1040  std::stringstream error_message;
1041  error_message
1042  << "The number of segments that present initial coordinates "
1043  << nsegments_initial_coordinates << " is different from "
1044  << "the\nnumber of segments that present final coordinates "
1045  << nsegments_final_coordinates << "\n\n";
1046  throw OomphLibError(error_message.str(),
1047  OOMPH_CURRENT_FUNCTION,
1048  OOMPH_EXCEPTION_LOCATION);
1049  } // if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1050 
1051  // Also check that the number of segments found in the previous
1052  // mesh is the same as the number of segments found in this mesh
1053  if (nsegments_initial_coordinates != nsegments)
1054  {
1055  std::stringstream error_message;
1056  error_message << "Working with boundary (" << b
1057  << ").\n The number of initial and "
1058  << "final coordinates (" << nsegments_initial_coordinates
1059  << ") is different from\n"
1060  << "the number of found segments (" << nsegments
1061  << ").\n\n";
1062  throw OomphLibError(error_message.str(),
1063  OOMPH_CURRENT_FUNCTION,
1064  OOMPH_EXCEPTION_LOCATION);
1065  } // if (nsegments_initial_coordinates != nsegments)
1066 #endif
1067 
1068  // Create a backup for the data from the original mesh
1069  // Backup for the coordinates
1070  Vector<Vector<double>> original_mesh_segment_initial_coordinate(
1071  nsegments);
1072  Vector<Vector<double>> original_mesh_segment_final_coordinate(nsegments);
1073  // Backup for the zeta values
1074  Vector<double> original_mesh_segment_initial_zeta(nsegments);
1075  Vector<double> original_mesh_segment_final_zeta(nsegments);
1076  // Backup for the arclengths
1077  Vector<double> original_mesh_segment_initial_arclength(nsegments);
1078  Vector<double> original_mesh_segment_final_arclength(nsegments);
1079  // Do the backup
1080  for (unsigned is = 0; is < nsegments; is++)
1081  {
1082  original_mesh_segment_initial_coordinate[is].resize(2);
1083  original_mesh_segment_final_coordinate[is].resize(2);
1084  for (unsigned k = 0; k < 2; k++)
1085  {
1086  original_mesh_segment_initial_coordinate[is][k] =
1087  original_mesh_pt->boundary_segment_initial_coordinate(b)[is][k];
1088  original_mesh_segment_final_coordinate[is][k] =
1089  original_mesh_pt->boundary_segment_final_coordinate(b)[is][k];
1090  }
1091  // Check if the boudary has an associated GeomObject
1092  if (this->boundary_geom_object_pt(b) != 0)
1093  {
1094  original_mesh_segment_initial_zeta[is] =
1095  original_mesh_pt->boundary_segment_initial_zeta(b)[is];
1096  original_mesh_segment_final_zeta[is] =
1097  original_mesh_pt->boundary_segment_final_zeta(b)[is];
1098  }
1099  else
1100  {
1101  original_mesh_segment_initial_arclength[is] =
1102  original_mesh_pt->boundary_segment_initial_arclength(b)[is];
1103  original_mesh_segment_final_arclength[is] =
1104  original_mesh_pt->boundary_segment_final_arclength(b)[is];
1105  }
1106  } // for (is < nsegments)
1107 
1108  // Clear all the storage
1109  Boundary_segment_inverted[b].clear();
1110  Boundary_segment_initial_coordinate[b].clear();
1111  Boundary_segment_final_coordinate[b].clear();
1112 
1113  Boundary_segment_initial_zeta[b].clear();
1114  Boundary_segment_final_zeta[b].clear();
1115 
1116  Boundary_segment_initial_arclength[b].clear();
1117  Boundary_segment_final_arclength[b].clear();
1118 
1119  // Identify each segment in the processor with the ones created
1120  // by the original mesh
1121  // -----------------------------------------------------------------
1122  // Keep track of the already identified segments
1123  std::map<unsigned, bool> segment_done;
1124  for (unsigned is = 0; is < nsegments; is++)
1125  {
1126 #ifdef PARANOID
1127  // Flag to know if the segment was identified
1128  bool found_original_segment = false;
1129 #endif
1130 
1131  // Get the initial and final coordinates of the current segment
1132  Vector<double> current_seg_initial_coord(2);
1133  Vector<double> current_seg_final_coord(2);
1134 
1135  // Get access to the initial element on the segment
1136  FiniteElement* current_seg_initial_ele_pt =
1137  segment_sorted_ele_pt[is].front();
1138 
1139  // Number of nodes
1140  const unsigned nnod = current_seg_initial_ele_pt->nnode();
1141 
1142  // Get the first node of the current segment
1143  Node* current_seg_first_node_pt =
1144  current_seg_initial_ele_pt->node_pt(0);
1145  if (is_inverted[current_seg_initial_ele_pt])
1146  {
1147  current_seg_first_node_pt =
1148  current_seg_initial_ele_pt->node_pt(nnod - 1);
1149  }
1150 
1151  // Get access to the last element on the segment
1152  FiniteElement* current_seg_last_ele_pt =
1153  segment_sorted_ele_pt[is].back();
1154 
1155  // Get the last node of the current segment
1156  Node* current_seg_last_node_pt =
1157  current_seg_last_ele_pt->node_pt(nnod - 1);
1158  if (is_inverted[current_seg_last_ele_pt])
1159  {
1160  current_seg_last_node_pt = current_seg_last_ele_pt->node_pt(0);
1161  }
1162 
1163  // Get the coordinates for the first and last seg node
1164  for (unsigned i = 0; i < 2; i++)
1165  {
1166  current_seg_initial_coord[i] = current_seg_first_node_pt->x(i);
1167  current_seg_final_coord[i] = current_seg_last_node_pt->x(i);
1168  }
1169 
1170  // We have got the initial and final coordinates of the current
1171  // segment, compare those with the initial and final coordinates
1172  // of the original mesh segments to identify which segments is
1173  // which
1174  for (unsigned orig_s = 0; orig_s < nsegments; orig_s++)
1175  {
1176  if (!segment_done[orig_s])
1177  {
1178  // Get the coordinates to compare
1179  Vector<double> initial_coordinate =
1180  original_mesh_segment_initial_coordinate[orig_s];
1181  Vector<double> final_coordinate =
1182  original_mesh_segment_final_coordinate[orig_s];
1183 
1184  // Compute the distance initial(current)-initial(original)
1185  // coordinates
1186  double dist =
1187  ((current_seg_initial_coord[0] - initial_coordinate[0]) *
1188  (current_seg_initial_coord[0] - initial_coordinate[0])) +
1189  ((current_seg_initial_coord[1] - initial_coordinate[1]) *
1190  (current_seg_initial_coord[1] - initial_coordinate[1]));
1191  dist = sqrt(dist);
1192 
1193  // If the initial node is the same, check for the last node
1194  if (dist < ToleranceForVertexMismatchInPolygons::Tolerable_error)
1195  {
1196  // Compute the distance final(current)-final(original)
1197  // coordinates
1198  dist = ((current_seg_final_coord[0] - final_coordinate[0]) *
1199  (current_seg_final_coord[0] - final_coordinate[0])) +
1200  ((current_seg_final_coord[1] - final_coordinate[1]) *
1201  (current_seg_final_coord[1] - final_coordinate[1]));
1202  dist = sqrt(dist);
1203 
1204  // The final node is the same, we have identified the
1205  // segments
1206  if (dist < ToleranceForVertexMismatchInPolygons::Tolerable_error)
1207  {
1208  // Store the index that relates the previous index with the
1209  // current one
1210  current_segment_to_original_segment_index[is] = orig_s;
1211 
1212  // In this case the segment is not inverted
1213  Boundary_segment_inverted[b].push_back(0);
1214 
1215  // Copy the initial and final coordinates for each segment
1216  Boundary_segment_initial_coordinate[b].push_back(
1217  initial_coordinate);
1218  Boundary_segment_final_coordinate[b].push_back(
1219  final_coordinate);
1220 
1221  // Check if the boundary has an associated GeomObject
1222  if (this->boundary_geom_object_pt(b) != 0)
1223  {
1224  // Copy the initial zeta value for the segment
1225  Boundary_segment_initial_zeta[b].push_back(
1226  original_mesh_segment_initial_zeta[orig_s]);
1227  Boundary_segment_final_zeta[b].push_back(
1228  original_mesh_segment_final_zeta[orig_s]);
1229  }
1230  else
1231  {
1232  // Copy the initial and final arclength for each
1233  // segment
1234  Boundary_segment_initial_arclength[b].push_back(
1235  original_mesh_segment_initial_arclength[orig_s]);
1236  Boundary_segment_final_arclength[b].push_back(
1237  original_mesh_segment_final_arclength[orig_s]);
1238  }
1239  // Mark the segment as done
1240  segment_done[orig_s] = true;
1241 #ifdef PARANOID
1242  found_original_segment = true;
1243 #endif
1244  break;
1245  } // The final(current) node matched with the
1246  // final(original) node
1247  } // The initial(current) node matched with the
1248  // initial(original) node
1249  else
1250  {
1251  // Check the inverted case Compute the distance
1252  // initial(current)-final(original) coordinates
1253  double dist_inv =
1254  ((current_seg_initial_coord[0] - final_coordinate[0]) *
1255  (current_seg_initial_coord[0] - final_coordinate[0])) +
1256  ((current_seg_initial_coord[1] - final_coordinate[1]) *
1257  (current_seg_initial_coord[1] - final_coordinate[1]));
1258  dist_inv = sqrt(dist_inv);
1259 
1260  // If the initial node is the same as the final node of
1261  // the segment, check for the last node
1262  if (dist_inv <
1263  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1264  {
1265  // Compute the distance final(current)-initial(original)
1266  // coordinates
1267  dist_inv =
1268  ((current_seg_final_coord[0] - initial_coordinate[0]) *
1269  (current_seg_final_coord[0] - initial_coordinate[0])) +
1270  ((current_seg_final_coord[1] - initial_coordinate[1]) *
1271  (current_seg_final_coord[1] - initial_coordinate[1]));
1272  dist_inv = sqrt(dist_inv);
1273 
1274  // The final node is the same as the initial node, we
1275  // have identified the segments
1276  if (dist_inv <
1277  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1278  {
1279  // Store the index that related the previous index with the
1280  // current one
1281  current_segment_to_original_segment_index[is] = orig_s;
1282 
1283  // In this case the segment is inverted
1284  Boundary_segment_inverted[b].push_back(1);
1285 
1286  // Copy the initial and final coordinates for each segment
1287  Boundary_segment_initial_coordinate[b].push_back(
1288  initial_coordinate);
1289  Boundary_segment_final_coordinate[b].push_back(
1290  final_coordinate);
1291 
1292  // Check that the boudary has an associated GeomObject
1293  if (this->boundary_geom_object_pt(b) != 0)
1294  {
1295  // Copy the initial zeta value for the segments
1296  Boundary_segment_initial_zeta[b].push_back(
1297  original_mesh_segment_initial_zeta[orig_s]);
1298  Boundary_segment_final_zeta[b].push_back(
1299  original_mesh_segment_final_zeta[orig_s]);
1300  }
1301  else
1302  {
1303  // Copy the initial and final arclength for each segment
1304  Boundary_segment_initial_arclength[b].push_back(
1305  original_mesh_segment_initial_arclength[orig_s]);
1306  Boundary_segment_final_arclength[b].push_back(
1307  original_mesh_segment_final_arclength[orig_s]);
1308  }
1309  // Mark the segment as done
1310  segment_done[orig_s] = true;
1311 #ifdef PARANOID
1312  found_original_segment = true;
1313 #endif
1314  break;
1315  } // The final(current) node matched with the
1316  // initial(original) node
1317  } // The initial(current) node matched with the
1318  // final(original) node
1319  } // else (the first(current) node did not matched with the
1320  // first(original) node. Else do the inverted case
1321 
1322  } // (!segment_done[orig_s])
1323 
1324  } // (orig_s < nsegments)
1325 
1326 #ifdef PARANOID
1327  if (!found_original_segment)
1328  {
1329  std::stringstream error_message;
1330  error_message
1331  << "The (" << is << ")-th segment on the current segment was not\n"
1332  << "found when trying to identify it with the original mesh's\n"
1333  << "segment coordinates\n";
1334  throw OomphLibError(error_message.str(),
1335  OOMPH_CURRENT_FUNCTION,
1336  OOMPH_EXCEPTION_LOCATION);
1337  } // if (!found_original_segment)
1338 #endif
1339  } // for (is < nsegments)
1340 
1341  } // if (nsegments > 0)
1342 
1343  // -------------------------------------------------------------------
1344  // Fourth: The original mesh is different from the current mesh
1345  // (this). For boundaries with no geom object associated check if it
1346  // is required to reverse the zeta values. In order to reverse the
1347  // zeta values it is required to previously compute the arclength of
1348  // the segments and store the nodes in a container (set). NOTE that
1349  // the setup_boundary_coordinate() method is not called for
1350  // boundaries with NO GeomObject associated, so this is the LAST
1351  // CHANCE to do it
1352  // -------------------------------------------------------------------
1353  // The original mesh is the same as the current mesh (this). The
1354  // setup_boundary_method() will be called only for the boundaries
1355  // with NO GeomObject associated
1356  // -------------------------------------------------------------------
1357  if (this != original_mesh_pt)
1358  {
1359  // Get the boundary arclength
1360 
1361  // Get the initial and final zeta values for the boundary
1362  // (arclength) from the original mesh
1363  Vector<double> first_node_zeta_coordinate =
1364  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1365  Vector<double> last_node_zeta_coordinate =
1366  original_mesh_pt->boundary_final_zeta_coordinate(b);
1367 
1368  // The boundary arclength is the maximum of the initial and final
1369  // zeta coordinate
1370  const double boundary_arclength =
1371  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
1372 
1373  for (unsigned is = 0; is < nsegments; is++)
1374  {
1375  // Here check if need to invert the elements and the boundary
1376  // coordinates for the segments in a boundary with no GeomObject
1377  // associated
1378  if (boundary_geom_object_pt(b) == 0)
1379  {
1380  // This case only applies for the initial and iterative mesh in
1381  // the adaptation process because the method
1382  // setup_boundary_coordinates() is called by the original mesh
1383  // for boundaries with no GeomObject associated
1384 
1385  // We are goind to check if it is necessary to invert the order
1386  // of the zeta values
1387 
1388  // Get the first and last node of the current segment and their
1389  // zeta values (arclength)
1390 
1391  // There is no need to check for nonhalo elements since the
1392  // container has only nonhalo face elements
1393 
1394  // Get access to the first element on the segment
1395  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
1396 
1397  // Number of nodes
1398  const unsigned nnod = first_ele_pt->nnode();
1399 
1400  // Get the first node of the current segment
1401  Node* first_node_pt = first_ele_pt->node_pt(0);
1402  if (is_inverted[first_ele_pt])
1403  {
1404  first_node_pt = first_ele_pt->node_pt(nnod - 1);
1405  }
1406 
1407  // Get access to the last element on the segment
1408  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
1409 
1410  // Get the last node of the current segment
1411  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
1412  if (is_inverted[last_ele_pt])
1413  {
1414  last_node_pt = last_ele_pt->node_pt(0);
1415  }
1416 
1417  // Get the zeta coordinates for the first and last node
1418  Vector<double> current_segment_initial_arclen(1);
1419  Vector<double> current_segment_final_arclen(1);
1420  // Is the segment in the current mesh (this) inverted?
1421  if (!Boundary_segment_inverted[b][is]) // Not inverted
1422  {
1423  first_node_pt->get_coordinates_on_boundary(
1424  b, current_segment_initial_arclen);
1425  last_node_pt->get_coordinates_on_boundary(
1426  b, current_segment_final_arclen);
1427  }
1428  else // Inverted
1429  {
1430  first_node_pt->get_coordinates_on_boundary(
1431  b, current_segment_final_arclen);
1432  last_node_pt->get_coordinates_on_boundary(
1433  b, current_segment_initial_arclen);
1434  }
1435 
1436  // Once the zeta values have been obtained check if they are set
1437  // in increasing or decreasing order
1438 
1439  // Flag to state that the values in the segment are in increasing
1440  // order
1441  bool increasing_order = false;
1442 
1443  // If the initial zeta value is smaller than the final zeta
1444  // value then they are in increasing order
1445  if (current_segment_initial_arclen[0] <
1446  current_segment_final_arclen[0])
1447  {
1448  increasing_order = true;
1449  }
1450  // If the initial zeta value is greater than the initial zeta
1451  // value then they are in decreasing order
1452  else if (current_segment_initial_arclen[0] >
1453  current_segment_final_arclen[0])
1454  {
1455  increasing_order = false;
1456  }
1457 #ifdef PARANOID
1458  else
1459  {
1460  std::stringstream error_message;
1461  error_message
1462  << "It was not possible to identify if the zeta values on "
1463  << "boundary (" << b << ")\nand segment (" << is
1464  << ") should go in "
1465  << "increasing or decreasing order.\n--- New mesh ---\n"
1466  << "Current segment initial arclength: ("
1467  << current_segment_initial_arclen[0] << ")\n"
1468  << "First node coordinates: (" << first_node_pt->x(0) << ", "
1469  << first_node_pt->x(1) << ")\n"
1470  << "Current segment final arclength: ("
1471  << current_segment_final_arclen[0] << ")\n"
1472  << "Last node coordinates: (" << last_node_pt->x(0) << ", "
1473  << last_node_pt->x(1) << ")\n"
1474  << "Current segment arclength: (" << segment_arclength[is]
1475  << ")\n";
1476  throw OomphLibError(error_message.str(),
1477  OOMPH_CURRENT_FUNCTION,
1478  OOMPH_EXCEPTION_LOCATION);
1479  }
1480 #endif
1481 
1482  // Now get the original initial and final arclengths and check
1483  // if they are in increasing or decreasing order
1484  const unsigned prev_s = current_segment_to_original_segment_index[is];
1485  const double original_segment_initial_arclength =
1486  original_mesh_pt->boundary_segment_initial_arclength(b)[prev_s];
1487  const double original_segment_final_arclength =
1488  original_mesh_pt->boundary_segment_final_arclength(b)[prev_s];
1489 
1490  // Flag to check if the values go in increasing or decreasing
1491  // order in the original mesh segment
1492  bool original_increasing_order = false;
1493 
1494  // Now check if the arclengths on the original mesh go in
1495  // increase or decrease order, this is also used to choose the
1496  // starting value to map the values in the current segment
1497  double starting_arclength = 0.0;
1498  if (original_segment_final_arclength >
1499  original_segment_initial_arclength)
1500  {
1501  // ... in increasing order in the original mesh ...
1502  original_increasing_order = true;
1503  // Select the starting arclength
1504  starting_arclength = original_segment_initial_arclength;
1505  }
1506  else if (original_segment_final_arclength <
1507  original_segment_initial_arclength)
1508  {
1509  // ... in decreasing order in the original mesh ...
1510  original_increasing_order = false;
1511  // Select the starting arclength
1512  starting_arclength = original_segment_final_arclength;
1513  }
1514 #ifdef PARANOID
1515  else
1516  {
1517  std::stringstream error_message;
1518  error_message
1519  << "It was not possible to identify if the zeta values on "
1520  << "boundary (" << b << ")\nand segment (" << is
1521  << ") should go in "
1522  << "increasing or decreasing order.\n--- Original mesh ---\n"
1523  << "Original segment initial arclength: ("
1524  << original_segment_initial_arclength << ")\n"
1525  << "Original segment final arclength: ("
1526  << original_segment_final_arclength << ")\n";
1527  throw OomphLibError(error_message.str(),
1528  OOMPH_CURRENT_FUNCTION,
1529  OOMPH_EXCEPTION_LOCATION);
1530  }
1531 #endif
1532 
1533  // Now scale the zeta values based considering if the zeta
1534  // values from the current mesh (this) go in the same order as
1535  // in the original mesh
1536  if (increasing_order && original_increasing_order)
1537  {
1538  // Current seg
1539  // |------|
1540  // 0 ---- 1
1541  //
1542  // Is mapped to the new values
1543  // |------|
1544  // a ---- b
1545  // a = original_segment_initial_arclength
1546  // b = original_segment_final_arclength
1547  // s = starting_arclength
1548  // The mapping is given by
1549  // new_z = s + z_old * (b - a)
1550 
1551  // Get the nodes associated to the segment
1552  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1553  // Go through all the nodes in the segment an change their
1554  // zeta values
1555  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1556  it != seg_nodes_pt.end();
1557  it++)
1558  {
1559  // Storing for the zeta value
1560  Vector<double> zeta(1);
1561  // Get each node
1562  Node* nod_pt = (*it);
1563  // Get the zeta value of the current node
1564  nod_pt->get_coordinates_on_boundary(b, zeta);
1565  // ... and re-assign it
1566  const double temp =
1567  starting_arclength + (zeta[0] * segment_arclength[is]);
1568  // The zeta value
1569  zeta[0] = temp / boundary_arclength;
1570  // Correct
1571  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1572  {
1573  zeta[0] = 1.0;
1574  }
1575  else if (std::fabs(zeta[0]) < 1.0e-14)
1576  {
1577  zeta[0] = 0.0;
1578  }
1579 
1580  // Set the new value
1581  nod_pt->set_coordinates_on_boundary(b, zeta);
1582  } // Go through all the nodes
1583  } // if (increasing_order && original_increasing_order)
1584  else if (!increasing_order && original_increasing_order)
1585  {
1586  // Current seg
1587  // |------|
1588  // 1 ---- 0
1589  //
1590  // Is mapped to the new values
1591  // |------|
1592  // a ---- b
1593  // a = original_segment_initial_arclength
1594  // b = original_segment_final_arclength
1595  // s = starting_arclength
1596  // The mapping is given by
1597  // new_z = s + (1.0 - z_old) * (b - a)
1598 
1599  // Get the nodes associated to the segment
1600  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1601  // Go through all the nodes in the segment an change their
1602  // zeta values
1603  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1604  it != seg_nodes_pt.end();
1605  it++)
1606  {
1607  // Storing for the zeta value
1608  Vector<double> zeta(1);
1609  // Get each node
1610  Node* nod_pt = (*it);
1611  // Get the zeta value of the current node
1612  nod_pt->get_coordinates_on_boundary(b, zeta);
1613  // ... and re-assign it
1614  const double temp =
1615  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1616  // The zeta value
1617  zeta[0] = temp / boundary_arclength;
1618  // Correct
1619  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1620  {
1621  zeta[0] = 1.0;
1622  }
1623  else if (std::fabs(zeta[0]) < 1.0e-14)
1624  {
1625  zeta[0] = 0.0;
1626  }
1627  // Set the new value
1628  nod_pt->set_coordinates_on_boundary(b, zeta);
1629  } // Go through all the nodes
1630  } // else if (!increasing_order && original_increasing_order)
1631  else if (increasing_order && !original_increasing_order)
1632  {
1633  // Current seg
1634  // |------|
1635  // 0 ---- 1
1636  //
1637  // Is mapped to the new values
1638  // |------|
1639  // b ---- a
1640  // a = original_segment_initial_arclength
1641  // b = original_segment_final_arclength
1642  // s = starting_arclength
1643  // The mapping is given by
1644  // new_z = s + (1.0 - z_old) * |(b - a)|
1645 
1646  // Get the nodes associated to the segment
1647  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1648  // Go through all the nodes in the segment an change their
1649  // zeta values
1650  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1651  it != seg_nodes_pt.end();
1652  it++)
1653  {
1654  // Storing for the zeta value
1655  Vector<double> zeta(1);
1656  // Get each node
1657  Node* nod_pt = (*it);
1658  // Get the zeta value of the current node
1659  nod_pt->get_coordinates_on_boundary(b, zeta);
1660  // ... and re-assign it
1661  const double temp =
1662  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1663  // The zeta value
1664  zeta[0] = temp / boundary_arclength;
1665  // Correct
1666  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1667  {
1668  zeta[0] = 1.0;
1669  }
1670  else if (std::fabs(zeta[0]) < 1.0e-14)
1671  {
1672  zeta[0] = 0.0;
1673  }
1674  // Set the new value
1675  nod_pt->set_coordinates_on_boundary(b, zeta);
1676  } // Go through all the nodes
1677  } // else if (increasing_order && !original_increasing_order)
1678  else if (!increasing_order && !original_increasing_order)
1679  {
1680  // Current seg
1681  // |------|
1682  // 0 ---- 1
1683  //
1684  // Is mapped to the new values
1685  // |------|
1686  // a ---- b
1687  // a = original_segment_initial_arclength
1688  // b = original_segment_final_arclength
1689  // s = starting_arclength
1690  // The mapping is given by
1691  // new_z = s + z_old * |(b - a)|
1692 
1693  // Get the nodes associated to the segment
1694  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1695  // Go through all the nodes in the segment an change their
1696  // zeta values
1697  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1698  it != seg_nodes_pt.end();
1699  it++)
1700  {
1701  // Storing for the zeta value
1702  Vector<double> zeta(1);
1703  // Get each node
1704  Node* nod_pt = (*it);
1705  // Get the zeta value of the current node
1706  nod_pt->get_coordinates_on_boundary(b, zeta);
1707  // ... and re-assign it
1708  const double temp =
1709  starting_arclength + (zeta[0] * segment_arclength[is]);
1710  // The zeta value
1711  zeta[0] = temp / boundary_arclength;
1712  // Correct
1713  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1714  {
1715  zeta[0] = 1.0;
1716  }
1717  else if (std::fabs(zeta[0]) < 1.0e-14)
1718  {
1719  zeta[0] = 0.0;
1720  }
1721  // Set the new value
1722  nod_pt->set_coordinates_on_boundary(b, zeta);
1723  } // Go through all the nodes
1724  } // else if (!increasing_order && !original_increasing_order)
1725 
1726 #ifdef PARANOID
1727  // Verify that the z values of the first and last node are not
1728  // out of the range [0,1]
1729  for (std::list<FiniteElement*>::iterator it_list =
1730  segment_sorted_ele_pt[is].begin();
1731  it_list != segment_sorted_ele_pt[is].end();
1732  it_list++)
1733  {
1734  // Number of nodes in the segment
1735  const unsigned nnod = (*it_list)->nnode();
1736 
1737  // Get the first node of the current segment
1738  Node* first_node_pt = (*it_list)->node_pt(0);
1739  if (is_inverted[(*it_list)])
1740  {
1741  first_node_pt = (*it_list)->node_pt(nnod - 1);
1742  }
1743 
1744  // Get the last node of the current segment
1745  Node* last_node_pt = (*it_list)->node_pt(nnod - 1);
1746  if (is_inverted[(*it_list)])
1747  {
1748  last_node_pt = (*it_list)->node_pt(0);
1749  }
1750 
1751  // The z value for the first node
1752  Vector<double> zeta(1);
1753  first_node_pt->get_coordinates_on_boundary(b, zeta);
1754  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1755  {
1756  std::ostringstream error_message;
1757  error_message
1758  << "The boundary coordinate of the first node on boundary ("
1759  << b << ")\nand segment (" << is << ") is out of the "
1760  << "allowed values [0,1]\n"
1761  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1762  << "The vertex coordinates are: (" << first_node_pt->x(0)
1763  << ", " << first_node_pt->x(1) << ")\n";
1764  throw OomphLibError(error_message.str(),
1765  OOMPH_CURRENT_FUNCTION,
1766  OOMPH_EXCEPTION_LOCATION);
1767  }
1768 
1769  // The z value for the last node
1770  last_node_pt->get_coordinates_on_boundary(b, zeta);
1771  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1772  {
1773  std::ostringstream error_message;
1774  error_message
1775  << "The boundary coordinate of the last node on boundary (" << b
1776  << ")\nand segment (" << is << ") is out of the "
1777  << "allowed values [0,1]\n"
1778  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1779  << "The vertex coordinates are: (" << last_node_pt->x(0) << ", "
1780  << last_node_pt->x(1) << ")\n";
1781  throw OomphLibError(error_message.str(),
1782  OOMPH_CURRENT_FUNCTION,
1783  OOMPH_EXCEPTION_LOCATION);
1784  }
1785  }
1786 #endif // #ifdef PARANOID
1787 
1788  } // if (boundary_geom_object_pt(b)==0)
1789 
1790  } // for (is < nsegments)
1791 
1792  } // if (this != original_mesh_pt)
1793 
1794  // ------------------------------------------------------------------
1795  // Copy the corrected (possible reversed) info. to the containers of
1796  // the current mesh
1797  // ------------------------------------------------------------------
1798  // Check if there are segments of b boundary in this processor
1799  if (nsegments > 0)
1800  {
1801  // Copy the initial and final coordinates
1802  Boundary_initial_coordinate[b] =
1803  original_mesh_pt->boundary_initial_coordinate(b);
1804 
1805  Boundary_final_coordinate[b] =
1806  original_mesh_pt->boundary_final_coordinate(b);
1807 
1808  // The initial and final zeta coordinates (In case of a geometric
1809  // object those are the limits of the geom object)
1810  Boundary_initial_zeta_coordinate[b] =
1811  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1812 
1813  Boundary_final_zeta_coordinate[b] =
1814  original_mesh_pt->boundary_final_zeta_coordinate(b);
1815 
1816  } // if (nsegments > 0)
1817 
1818  // Set the flag to indicate that the zeta values have been assigned
1819  // for the current boundary
1820  Assigned_segments_initial_zeta_values[b] = true;
1821 
1822  // Clean all the created face elements
1823  for (unsigned i = 0; i < nele; i++)
1824  {
1825  delete face_el_pt[i];
1826  face_el_pt[i] = 0;
1827  }
1828  }
1829 
1830  //======================================================================
1831  /// \short Compute the boundary segments connectivity for those
1832  /// boundaries that were splited during the distribution process
1833  /// and also the initial zeta values for each segment (the initial
1834  /// and final boundary nodes coordinates)
1835  //======================================================================
1836  template<class ELEMENT>
1839  const unsigned& b)
1840  {
1841  // ------------------------------------------------------------------
1842  // First: Get the face elements associated with the current boundary
1843  // ------------------------------------------------------------------
1844 
1845  // Get the communicator of the mesh
1846  OomphCommunicator* comm_pt = this->communicator_pt();
1847 
1848  // Get the number of processors
1849  const unsigned nproc = comm_pt->nproc();
1850  // Get the rank of the current processor
1851  const unsigned my_rank = comm_pt->my_rank();
1852 
1853  // Temporary storage for face elements
1854  Vector<FiniteElement*> all_face_ele_pt;
1855 
1856  // Flag to know whether we are working with an internal open curve
1857  // and then re-assign the initial and final zeta coordinates for
1858  // each segment (only used when the mesh is distributed)
1859  bool is_internal_boundary = false;
1860 
1861  // map to associate the face element to the bulk element, necessary
1862  // to attach halo face elements at both sides of each found segment
1863  std::map<FiniteElement*, FiniteElement*> face_to_bulk_element_pt;
1864 
1865  // Select the boundary face elements, using the criteria of highest
1866  // processor in charge and bottom-left element
1867  select_boundary_face_elements(
1868  all_face_ele_pt, b, is_internal_boundary, face_to_bulk_element_pt);
1869 
1870  // Get the number of face elements
1871  const unsigned n_all_face_ele = all_face_ele_pt.size();
1872 
1873  // ----------------------------------------------------------------
1874  // Second: Sort the face elements, only consider nonhalo elements
1875  // ----------------------------------------------------------------
1876 
1877  // A flag vector to mark those face elements that are considered as
1878  // halo in the current processor
1879  std::vector<bool> is_halo_face_element(n_all_face_ele, false);
1880 
1881  // Count the total number of non halo face elements
1882  unsigned nnon_halo_face_elements = 0;
1883 
1884  // Only mark the face elements as halo if the mesh is marked as
1885  // distributed
1886  for (unsigned ie = 0; ie < n_all_face_ele; ie++)
1887  {
1888  FiniteElement* face_ele_pt = all_face_ele_pt[ie];
1889  // Get the bulk element
1890  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
1891  // Check if the bulk element is halo
1892  if (!tmp_bulk_ele_pt->is_halo())
1893  {
1894  // Set the flag for non halo element
1895  is_halo_face_element[ie] = false;
1896  // Increase the non halo elements counter
1897  nnon_halo_face_elements++;
1898  }
1899  else
1900  {
1901  // Mark the face element as halo
1902  is_halo_face_element[ie] = true;
1903  }
1904 
1905  } // for (ie < n_ele)
1906 
1907  // Get the total number of halo face elements
1908  const unsigned nhalo_face_element =
1909  n_all_face_ele - nnon_halo_face_elements;
1910 
1911  // The vector of list to store the "segments" that compound the
1912  // boundary (segments may appear only in a distributed mesh)
1913  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
1914 
1915  // Number of already sorted face elements (only nonhalo elements for
1916  // a distributed mesh)
1917  unsigned nsorted_face_elements = 0;
1918 
1919  // Keep track of who's done (this apply to nonhalo only, remember we
1920  // are only working with halo elements)
1921  std::map<FiniteElement*, bool> done_el;
1922 
1923  // Keep track of which element is inverted (in distributed mesh the
1924  // elements may be inverted with respect to the segment they belong)
1925  std::map<FiniteElement*, bool> is_inverted;
1926 
1927  // Iterate until all possible segments have been created
1928  while (nsorted_face_elements < nnon_halo_face_elements)
1929  {
1930  // The ordered list of face elements (in a distributed mesh a
1931  // collection of contiguous face elements define a segment)
1932  std::list<FiniteElement*> sorted_el_pt;
1933  sorted_el_pt.clear();
1934 
1935 #ifdef PARANOID
1936  // Select an initial element for the segment (the first not done
1937  // nonhalo element)
1938  bool found_initial_face_element = false;
1939 #endif
1940 
1941  FiniteElement* ele_face_pt = 0;
1942 
1943  unsigned iface = 0;
1944  for (iface = 0; iface < n_all_face_ele; iface++)
1945  {
1946  if (!is_halo_face_element[iface])
1947  {
1948  ele_face_pt = all_face_ele_pt[iface];
1949  // If not done then take it as initial face element
1950  if (!done_el[ele_face_pt])
1951  {
1952 #ifdef PARANOID
1953  found_initial_face_element = true;
1954 #endif
1955  nsorted_face_elements++;
1956  iface++; // The next element number
1957  sorted_el_pt.push_back(ele_face_pt);
1958  // Mark as done
1959  done_el[ele_face_pt] = true;
1960  break;
1961  }
1962  }
1963  } // for (iface < nele)
1964 
1965 #ifdef PARANOID
1966  if (!found_initial_face_element)
1967  {
1968  std::ostringstream error_message;
1969  error_message
1970  << "Could not find an initial face element for the current segment\n";
1971  // << "----- Possible memory leak -----\n";
1972  throw OomphLibError(error_message.str(),
1973  OOMPH_CURRENT_FUNCTION,
1974  OOMPH_EXCEPTION_LOCATION);
1975  }
1976 #endif
1977 
1978  // Number of nodes
1979  const unsigned nnod = ele_face_pt->nnode();
1980 
1981  // Left and rightmost nodes (the left and right nodes of the
1982  // current face element)
1983  Node* left_node_pt = ele_face_pt->node_pt(0);
1984  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
1985 
1986  // Continue iterating if a new face element has been added to the
1987  // list
1988  bool face_element_added = false;
1989 
1990  // While a new face element has been added to the set of sorted
1991  // face elements then re-iterate
1992  do
1993  {
1994  // Start from the next face element since we have already added
1995  // the previous one as the initial face element (any previous
1996  // face element had to be added on previous iterations)
1997  for (unsigned iiface = iface; iiface < n_all_face_ele; iiface++)
1998  {
1999  // Re-start flag
2000  face_element_added = false;
2001 
2002  // Get the candidate element
2003  ele_face_pt = all_face_ele_pt[iiface];
2004 
2005  // Check that the candidate element has not been done and is
2006  // not a halo element
2007  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2008  {
2009  // Get the left and right nodes of the current element
2010  Node* local_left_node_pt = ele_face_pt->node_pt(0);
2011  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
2012 
2013  // New element fits at the left of segment and is not inverted
2014  if (left_node_pt == local_right_node_pt)
2015  {
2016  left_node_pt = local_left_node_pt;
2017  sorted_el_pt.push_front(ele_face_pt);
2018  is_inverted[ele_face_pt] = false;
2019  face_element_added = true;
2020  }
2021  // New element fits at the left of segment and is inverted
2022  else if (left_node_pt == local_left_node_pt)
2023  {
2024  left_node_pt = local_right_node_pt;
2025  sorted_el_pt.push_front(ele_face_pt);
2026  is_inverted[ele_face_pt] = true;
2027  face_element_added = true;
2028  }
2029  // New element fits on the right of segment and is not inverted
2030  else if (right_node_pt == local_left_node_pt)
2031  {
2032  right_node_pt = local_right_node_pt;
2033  sorted_el_pt.push_back(ele_face_pt);
2034  is_inverted[ele_face_pt] = false;
2035  face_element_added = true;
2036  }
2037  // New element fits on the right of segment and is inverted
2038  else if (right_node_pt == local_right_node_pt)
2039  {
2040  right_node_pt = local_left_node_pt;
2041  sorted_el_pt.push_back(ele_face_pt);
2042  is_inverted[ele_face_pt] = true;
2043  face_element_added = true;
2044  }
2045 
2046  if (face_element_added)
2047  {
2048  done_el[ele_face_pt] = true;
2049  nsorted_face_elements++;
2050  break;
2051  }
2052 
2053  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2054  } // for (iiface<nnon_halo_face_element)
2055  } while (face_element_added &&
2056  (nsorted_face_elements < nnon_halo_face_elements));
2057 
2058  // Store the created segment in the vector of segments
2059  segment_sorted_ele_pt.push_back(sorted_el_pt);
2060 
2061  } // while(nsorted_face_elements < nnon_halo_face_elements);
2062 
2063  // -----------------------------------------------------------------
2064  // Third: We have the face elements sorted (in segments), now assign
2065  // boundary coordinates to the nodes in the segments, this is the
2066  // LOCAL boundary coordinate and further communication is needed to
2067  // compute the GLOBAL boundary coordinates
2068  // -----------------------------------------------------------------
2069 
2070  // Vector of sets that stores the nodes of each segment based on a
2071  // lexicographically order starting from the bottom left node of
2072  // each segment
2073  Vector<std::set<Node*>> segment_all_nodes_pt;
2074 
2075  // The number of segments in this processor
2076  const unsigned nsegments = segment_sorted_ele_pt.size();
2077  // DEBP(nsegments);
2078 
2079 #ifdef PARANOID
2080  if (nnon_halo_face_elements > 0 && nsegments == 0)
2081  {
2082  std::ostringstream error_message;
2083  error_message
2084  << "The number of segments is zero, but the number of nonhalo\n"
2085  << "elements is: (" << nnon_halo_face_elements << ")\n";
2086  throw OomphLibError(
2087  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2088  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
2089 #endif
2090 
2091  // The arclength of each segment in the current processor
2092  Vector<double> segment_arclength(nsegments);
2093 
2094  // The number of vertices of each segment
2095  Vector<unsigned> nvertices_per_segment(nsegments);
2096 
2097  // The initial zeta for the segment
2098  Vector<double> initial_zeta_segment(nsegments);
2099 
2100  // The final zeta for the segment
2101  Vector<double> final_zeta_segment(nsegments);
2102 
2103  // Go through all the segments and compute its ARCLENGTH (if the
2104  // boundary has a GeomObject associated then assign the initial and
2105  // final zeta values for the segment)
2106  for (unsigned is = 0; is < nsegments; is++)
2107  {
2108 #ifdef PARANOID
2109  if (segment_sorted_ele_pt[is].size() == 0)
2110  {
2111  std::ostringstream error_message;
2112  error_message << "The (" << is << ")-th segment has no elements\n";
2113  throw OomphLibError(error_message.str(),
2114  OOMPH_CURRENT_FUNCTION,
2115  OOMPH_EXCEPTION_LOCATION);
2116  } // if (segment_sorted_ele_pt[is].size() == 0)
2117 #endif
2118 
2119  // Get access to the first element on the segment
2120  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2121 
2122  // Number of nodes
2123  const unsigned nnod = first_ele_pt->nnode();
2124 
2125  // Get the first node of the current segment
2126  Node* first_node_pt = first_ele_pt->node_pt(0);
2127  if (is_inverted[first_ele_pt])
2128  {
2129  first_node_pt = first_ele_pt->node_pt(nnod - 1);
2130  }
2131 
2132  // Coordinates of left node
2133  double x_left = first_node_pt->x(0);
2134  double y_left = first_node_pt->x(1);
2135 
2136  // Initialise boundary coordinate (local boundary coordinate for
2137  // boundaries with more than one segment)
2138  Vector<double> zeta(1, 0.0);
2139 
2140  // If we have associated a GeomObject then it is not necessary to
2141  // compute the arclength, only read the values from the nodes at
2142  // the edges and set the initial and final zeta segment values
2143  if (this->boundary_geom_object_pt(b) != 0)
2144  {
2145  // Get the initial node coordinate
2146  first_node_pt->get_coordinates_on_boundary(b, zeta);
2147  // Set the initial zeta segment value
2148  initial_zeta_segment[is] = zeta[0];
2149 
2150  // Get access to the last element on the segment
2151  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2152 
2153  // Get the last node of the current segment
2154  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
2155  if (is_inverted[last_ele_pt])
2156  {
2157  last_node_pt = last_ele_pt->node_pt(0);
2158  }
2159 
2160  // Get the final node coordinate
2161  last_node_pt->get_coordinates_on_boundary(b, zeta);
2162  // Set the final zeta segment value
2163  final_zeta_segment[is] = zeta[0];
2164  }
2165 
2166  // Sort the nodes in the segment (lexicographically bottom left
2167  // node)
2168  std::set<Node*> local_nodes_pt;
2169  // Insert the first node
2170  local_nodes_pt.insert(first_node_pt);
2171 
2172  // Now loop over nodes in order and increase the ARCLENGTH
2173  for (std::list<FiniteElement*>::iterator it =
2174  segment_sorted_ele_pt[is].begin();
2175  it != segment_sorted_ele_pt[is].end();
2176  it++)
2177  {
2178  // Get the pointer to the element
2179  FiniteElement* el_pt = (*it);
2180 
2181  // Start node and increment
2182  unsigned k_nod = 1;
2183  int nod_diff = 1;
2184  // Access nodes in reverse?
2185  if (is_inverted[el_pt])
2186  {
2187  k_nod = nnod - 2;
2188  nod_diff = -1;
2189  }
2190 
2191  // Loop over nodes in the face element
2192  for (unsigned j = 1; j < nnod; j++)
2193  {
2194  Node* nod_pt = el_pt->node_pt(k_nod);
2195  k_nod += nod_diff;
2196 
2197  // Coordinates of right node
2198  double x_right = nod_pt->x(0);
2199  double y_right = nod_pt->x(1);
2200 
2201  // Increment boundary coordinate (the arclength)
2202  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
2203  (y_right - y_left) * (y_right - y_left));
2204 
2205  // When we have a GeomObject associated to the boundary we already
2206  // know the zeta values for the nodes, there is no need to compute
2207  // the arclength
2208  // if (this->boundary_geom_object_pt(b)==0)
2209  // {
2210  // // Set boundary coordinate
2211  // // nod_pt->set_coordinates_on_boundary(b, zeta);
2212  // }
2213 
2214  // Increment reference coordinate
2215  x_left = x_right;
2216  y_left = y_right;
2217 
2218  // Get lexicographically bottom left node but only
2219  // use vertex nodes as candidates
2220  local_nodes_pt.insert(nod_pt);
2221 
2222  } // for (j < nnod)
2223 
2224  } // iterator over the elements in the segment
2225 
2226  // Info. to be passed to other processors
2227  // The initial arclength for the segment that goes after this depends
2228  // on the current segment arclength
2229  segment_arclength[is] = zeta[0];
2230 
2231  // Info. to be passed to the other processors
2232  // The initial vertex number for the segment that goes after this
2233  // depends on the current segment vertices number
2234  nvertices_per_segment[is] = local_nodes_pt.size();
2235 
2236  // Add the nodes for the corresponding segment in the container
2237  segment_all_nodes_pt.push_back(local_nodes_pt);
2238 
2239  // The attaching of the halo elements at both sides of the segments is
2240  // performed only if segments connectivity needs to be computed
2241 
2242  } // for (is < nsegments)
2243 
2244  // Container to store the number of vertices before each segment,
2245  // initialise to zero in case we have a non distributed boundary
2246  Vector<unsigned> nvertices_before_segment(nsegments, 0);
2247 
2248  // Store the initial arclength for each segment of boundary in the
2249  // current processor, initalise to zero in case we have a non
2250  // distributed boundary
2251  Vector<double> initial_segment_arclength(nsegments, 0.0);
2252 
2253  // Info. to be passed to other processors
2254  // If the boundary is distributed we need to know which processors does
2255  // have the initial and final segments, this helps to get the first and
2256  // last nodes coordinates (info. used to scale the bound coordinates)
2257 
2258  // Processors with the initial and final segment
2259  unsigned proc_with_initial_seg = 0;
2260  unsigned proc_with_final_seg = 0;
2261 
2262  // ... and the index of those segments (only of interest in the
2263  // processors that have the initial and final segments)
2264  unsigned initial_segment = 0;
2265  unsigned final_segment = 0;
2266 
2267  // Each segment needs to know whether it has to be inverted or not
2268  // Store whether a segment needs to be inverted or not
2269  Vector<unsigned> segment_inverted(nsegments);
2270 
2271  // Before attaching the halo elements create a copy of the data
2272  // structure without halo elements
2273  Vector<std::list<FiniteElement*>> segment_sorted_nonhalo_ele_pt(nsegments);
2274  for (unsigned is = 0; is < nsegments; is++)
2275  {
2276  for (std::list<FiniteElement*>::iterator it_seg =
2277  segment_sorted_ele_pt[is].begin();
2278  it_seg != segment_sorted_ele_pt[is].end();
2279  it_seg++)
2280  {
2281  segment_sorted_nonhalo_ele_pt[is].push_back((*it_seg));
2282  }
2283 
2284  } // for (is < nsegments)
2285 
2286  // --------------------------------------------------------------
2287  // Attach the halo elements at both sides of the segments
2288  for (unsigned is = 0; is < nsegments; is++)
2289  {
2290  // Get access to the first element on the segment
2291  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2292 
2293  // Number of nodes
2294  const unsigned nnod = first_ele_pt->nnode();
2295 
2296  // Get the first node of the current segment
2297  Node* first_node_pt = first_ele_pt->node_pt(0);
2298  if (is_inverted[first_ele_pt])
2299  {
2300  first_node_pt = first_ele_pt->node_pt(nnod - 1);
2301  }
2302 
2303  // Get access to the last element on the segment
2304  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2305 
2306  // Get the last node of the current segment
2307  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
2308  if (is_inverted[last_ele_pt])
2309  {
2310  last_node_pt = last_ele_pt->node_pt(0);
2311  }
2312 
2313  // -----------------------------------------------------------------
2314  // Fourth: Now attach the halo elements to the left and right side
2315  // of each segment
2316  // -----------------------------------------------------------------
2317  bool attached_left_halo = false;
2318  bool attached_right_halo = false;
2319  if (nhalo_face_element > 0)
2320  {
2321  for (unsigned iiface = 0; iiface < n_all_face_ele; iiface++)
2322  {
2323  // Get the candidate element
2324  FiniteElement* halo_face_ele_pt = all_face_ele_pt[iiface];
2325 
2326  // Check that the element is a halo face element, we do not check
2327  // if the element has been already done since the halo elements
2328  // may be connected to more than one segment (2 at most), to the
2329  // left and right of different segments
2330  //
2331  // Segment k Halo Segment r
2332  // |---|---|---| |xxx| |---|---|---|
2333  //
2334  // Segment k Halo Segment r
2335  // |---|---|---|xxx|---|---|---|
2336  //
2337  if (is_halo_face_element[iiface])
2338  {
2339  // Get its left and right nodes
2340  Node* left_node_pt = halo_face_ele_pt->node_pt(0);
2341  Node* right_node_pt = halo_face_ele_pt->node_pt(nnod - 1);
2342  // The halo element fits to the left of segment
2343  if (!attached_left_halo && (first_node_pt == right_node_pt ||
2344  first_node_pt == left_node_pt))
2345  {
2346  // Add the halo element to the left of the segment
2347  segment_sorted_ele_pt[is].push_front(halo_face_ele_pt);
2348 
2349  // Once a halo face element has been added to the left
2350  // mark as found halo to the left
2351  attached_left_halo = true;
2352  }
2353  // The halo element fits to the right of the segment
2354  else if (!attached_right_halo && (last_node_pt == left_node_pt ||
2355  last_node_pt == right_node_pt))
2356  {
2357  // Add the halo element to the right of the segment
2358  segment_sorted_ele_pt[is].push_back(halo_face_ele_pt);
2359  // Once a halo face element has been added to the right
2360  // mark as found halo to the right
2361  attached_right_halo = true;
2362  }
2363  // If we have already found elements to left and right then
2364  // break the loop
2365  if (attached_left_halo && attached_right_halo)
2366  {
2367  break;
2368  }
2369 
2370  } // if (is_halo_face_element[iiface])
2371 
2372  } // for (iiface < nel)
2373 
2374  } // if (nhalo_face_element > 0)
2375 
2376  } // for (is < nsegments)
2377 
2378  // The segments now have local coordinates assigned and halo
2379  // elements attached to them. Store that info. in the corresponding
2380  // data structures and be ready to send that info. to a root
2381  // processor. The root processor will be in charge of computing the
2382  // boundary coordinates for each segment of the boundary.
2383 
2384  // For each segment store the following information
2385  // --------------------------------------------------------------------
2386  // Stores the "rank" of the processor to the left of each segment,
2387  // zero if there is no processor to the left which states that the
2388  // segment is the first one on the boundary
2389  Vector<unsigned> left_processor_plus_one(nsegments);
2390 
2391  // Stores the "rank" of the processor to the right of each segment,
2392  // zero if there is no processor to the right which states that the
2393  // segment is the last one on the boundary
2394  Vector<unsigned> right_processor_plus_one(nsegments);
2395 
2396  // The id. of the halo element to the left of the segment, note that
2397  // this info. is not necessary if there is no processor to the left
2398  // of the segment
2399  Vector<unsigned> left_halo_element(nsegments);
2400 
2401  // The id. of the halo element to the right of the segment, note that
2402  // this info. is not necessary if there is no processor to the right
2403  // of the segment
2404  Vector<unsigned> right_halo_element(nsegments);
2405 
2406  // The id. of the haloed element to the left of the segment, note that
2407  // this info. is not necessary if there is no processor to the left
2408  // of the segment
2409  Vector<unsigned> left_haloed_element(nsegments);
2410 
2411  // The id. of the haloed element to the right of the segment, note
2412  // that this info. is not necessary if there is no processor to the
2413  // right of the segment
2414  Vector<unsigned> right_haloed_element(nsegments);
2415 
2416  // Go through all the segments and get the info.
2417  for (unsigned is = 0; is < nsegments; is++)
2418  {
2419  // Get access to the left most face element on the segment
2420  FiniteElement* left_face_ele_pt = segment_sorted_ele_pt[is].front();
2421 
2422  // Get the corresponding bulk element and check whether it is a halo
2423  // element or not
2424  FiniteElement* tmp_left_bulk_ele_pt =
2425  face_to_bulk_element_pt[left_face_ele_pt];
2426 
2427  // Check if the bulk element is halo
2428  if (tmp_left_bulk_ele_pt->is_halo())
2429  {
2430  // Then store the corresponding info.
2431  int left_proc = tmp_left_bulk_ele_pt->non_halo_proc_ID();
2432 #ifdef PARANOID
2433  if (left_proc < 0)
2434  {
2435  std::ostringstream error_message;
2436  error_message
2437  << "The current bulk element (left) is marked as halo but "
2438  << "the processor holding\nthe non-halo counterpart is "
2439  << "negative!\n";
2440  throw OomphLibError(error_message.str(),
2441  OOMPH_CURRENT_FUNCTION,
2442  OOMPH_EXCEPTION_LOCATION);
2443  }
2444 #endif
2445  // The processor "rank" to the left
2446  unsigned left_processor = static_cast<unsigned>(left_proc);
2447  left_processor_plus_one[is] = left_processor + 1;
2448 
2449  // Now get the id of the halo element to the left
2450  GeneralisedElement* left_element_pt = tmp_left_bulk_ele_pt;
2451 
2452  // Get the halo elements with left processor
2453  Vector<GeneralisedElement*> left_halo_element_pt =
2454  this->halo_element_pt(left_processor);
2455 
2456 #ifdef PARANOID
2457  // Flag to state that the halo element was found
2458  bool left_halo_element_found = false;
2459 #endif
2460 
2461  const unsigned n_halo_left = left_halo_element_pt.size();
2462  for (unsigned lh = 0; lh < n_halo_left; lh++)
2463  {
2464  if (left_element_pt == left_halo_element_pt[lh])
2465  {
2466  left_halo_element[is] = lh;
2467 #ifdef PARANOID
2468  left_halo_element_found = true;
2469 #endif
2470  break;
2471  }
2472  } // for (lh < n_halo_left)
2473 
2474 #ifdef PARANOID
2475  if (!left_halo_element_found)
2476  {
2477  std::ostringstream error_message;
2478  error_message
2479  << "The current bulk element (left) marked as halo was "
2480  << "not found in the vector of halo\nelements associated "
2481  << "with the (" << left_processor << ") processor.\n\n";
2482  throw OomphLibError(error_message.str(),
2483  OOMPH_CURRENT_FUNCTION,
2484  OOMPH_EXCEPTION_LOCATION);
2485  } // if (!left_halo_element_found)
2486 #endif
2487 
2488  // Get the left-most nonhalo element (use the backup list of
2489  // nonhalo elements)
2490  left_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].front();
2491 
2492  // Get the corresponding bulk element
2493  tmp_left_bulk_ele_pt = face_to_bulk_element_pt[left_face_ele_pt];
2494 
2495 #ifdef PARANOID
2496  // This element should not be marked as halo
2497  if (tmp_left_bulk_ele_pt->is_halo())
2498  {
2499  std::ostringstream error_message;
2500  error_message
2501  << "The bulk element represetation of the left-most nonhalo face\n"
2502  << "element of the current segment (" << is
2503  << ") is marked as halo,\n"
2504  << "but the face element created from it is nonhalo\n";
2505  throw OomphLibError(error_message.str(),
2506  OOMPH_CURRENT_FUNCTION,
2507  OOMPH_EXCEPTION_LOCATION);
2508  } // if (tmp_left_bulk_ele_pt->is_halo())
2509 #endif
2510 
2511  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2512  // to search in the haloed vector
2513  left_element_pt = tmp_left_bulk_ele_pt;
2514 
2515 #ifdef PARANOID
2516  // Flag to state that the haloed element was found
2517  bool left_haloed_element_found = false;
2518 #endif
2519 
2520  // Now get the id for the haloed element to the left, get the
2521  // haloed elements from the processor to the left
2522  Vector<GeneralisedElement*> left_haloed_element_pt =
2523  this->haloed_element_pt(left_processor);
2524 
2525  const unsigned nhaloed_left = left_haloed_element_pt.size();
2526  for (unsigned lhd = 0; lhd < nhaloed_left; lhd++)
2527  {
2528  if (left_element_pt == left_haloed_element_pt[lhd])
2529  {
2530  left_haloed_element[is] = lhd;
2531 #ifdef PARANOID
2532  left_haloed_element_found = true;
2533 #endif
2534  break;
2535  }
2536  } // for (lhd < nhaloed_left)
2537 
2538 #ifdef PARANOID
2539  if (!left_haloed_element_found)
2540  {
2541  std::ostringstream error_message;
2542  error_message
2543  << "The current bulk element (left) marked as haloed was "
2544  << "not found in the vector of haloed\nelements associated "
2545  << "with processor (" << left_processor << ").\n";
2546  throw OomphLibError(error_message.str(),
2547  OOMPH_CURRENT_FUNCTION,
2548  OOMPH_EXCEPTION_LOCATION);
2549  }
2550 #endif
2551  } // if (tmp_left_bulk_ele_pt->is_halo())
2552  else
2553  {
2554  // If not halo then state the info. to indicate that
2555  left_processor_plus_one[is] = 0;
2556  // Null this info.
2557  left_halo_element[is] = 0;
2558  // Null this info.
2559  left_haloed_element[is] = 0;
2560  }
2561 
2562  // Get access to the right most face element on the segment
2563  FiniteElement* right_face_ele_pt = segment_sorted_ele_pt[is].back();
2564 
2565  // Get the corresponding bulk element and check whether it is
2566  // a halo element or not
2567  FiniteElement* tmp_right_bulk_ele_pt =
2568  face_to_bulk_element_pt[right_face_ele_pt];
2569 
2570  // Check if the bulk element is halo
2571  if (tmp_right_bulk_ele_pt->is_halo())
2572  {
2573  // Then store the corresponding info.
2574  int right_proc = tmp_right_bulk_ele_pt->non_halo_proc_ID();
2575 #ifdef PARANOID
2576  if (right_proc < 0)
2577  {
2578  std::ostringstream error_message;
2579  error_message
2580  << "The current bulk element (right) is marked as halo but "
2581  << "the processor holding\nthe non-halo counterpart is "
2582  << "negative!\n";
2583  throw OomphLibError(error_message.str(),
2584  "TriangleMesh::compute_boundary_segments_"
2585  "connectivity_and_initial_zeta_values()",
2586  OOMPH_EXCEPTION_LOCATION);
2587  }
2588 #endif
2589  // The processor "rank" to the right
2590  unsigned right_processor = static_cast<unsigned>(right_proc);
2591  right_processor_plus_one[is] = right_processor + 1;
2592 
2593  // Now get the id of the halo element to the right
2594  GeneralisedElement* right_element_pt = tmp_right_bulk_ele_pt;
2595 
2596  // Get the halo elements with right processor
2597  Vector<GeneralisedElement*> right_halo_element_pt =
2598  this->halo_element_pt(right_processor);
2599 
2600 #ifdef PARANOID
2601  // Flag to state that the halo element was found
2602  bool right_halo_element_found = false;
2603 #endif
2604 
2605  const unsigned nhalo_right = right_halo_element_pt.size();
2606  for (unsigned rh = 0; rh < nhalo_right; rh++)
2607  {
2608  if (right_element_pt == right_halo_element_pt[rh])
2609  {
2610  right_halo_element[is] = rh;
2611 #ifdef PARANOID
2612  right_halo_element_found = true;
2613 #endif
2614  break;
2615  }
2616  } // for (rh < nhalo_right)
2617 #ifdef PARANOID
2618  if (!right_halo_element_found)
2619  {
2620  std::ostringstream error_message;
2621  error_message
2622  << "The current bulk element (right) marked as halo was not "
2623  << "found in the vector of halo\nelements associated with "
2624  << "the (" << right_processor << ") processor.\n\n";
2625  throw OomphLibError(error_message.str(),
2626  "TriangleMesh::compute_boundary_segments_"
2627  "connectivity_and_initial_zeta_values()",
2628  OOMPH_EXCEPTION_LOCATION);
2629  }
2630 #endif
2631 
2632  // Get the right-most nonhalo element (use the backup list of
2633  // nonhalo elements)
2634  right_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
2635 
2636  // Get the corresponding bulk element
2637  tmp_right_bulk_ele_pt = face_to_bulk_element_pt[right_face_ele_pt];
2638 #ifdef PARANOID
2639  // This element should not be marked as halo
2640  if (tmp_right_bulk_ele_pt->is_halo())
2641  {
2642  std::ostringstream error_message;
2643  error_message
2644  << "The bulk element represetation of the right-most nonhalo face\n"
2645  << "element of the current segment (" << is
2646  << ") is marked as halo,\n"
2647  << "but the face element created from it is nonhalo\n";
2648  throw OomphLibError(error_message.str(),
2649  "TriangleMesh::compute_boundary_segments_"
2650  "connectivity_and_initial_zeta_values()",
2651  OOMPH_EXCEPTION_LOCATION);
2652  } // if (tmp_right_bulk_ele_pt->is_halo())
2653 #endif
2654 
2655  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2656  // to search in the haloed vector
2657  right_element_pt = tmp_right_bulk_ele_pt;
2658 
2659 #ifdef PARANOID
2660  // Flag to state that the haloed element was found
2661  bool right_haloed_element_found = false;
2662 #endif
2663 
2664  // Now get the id for the haloed element to the right
2665  Vector<GeneralisedElement*> right_haloed_element_pt =
2666  this->haloed_element_pt(right_processor);
2667 
2668  const unsigned nhaloed_right = right_haloed_element_pt.size();
2669  for (unsigned rhd = 0; rhd < nhaloed_right; rhd++)
2670  {
2671  if (right_element_pt == right_haloed_element_pt[rhd])
2672  {
2673  right_haloed_element[is] = rhd;
2674 #ifdef PARANOID
2675  right_haloed_element_found = true;
2676 #endif
2677  break;
2678  }
2679  } // for (rhd < nhaloed_right)
2680 
2681 #ifdef PARANOID
2682  if (!right_haloed_element_found)
2683  {
2684  std::ostringstream error_message;
2685  error_message
2686  << "The current bulk element (right) marked as haloed was not "
2687  << "found in the vector of haloed\nelements associated with "
2688  << "the (" << right_processor << ") processor.\n\n";
2689  throw OomphLibError(error_message.str(),
2690  "TriangleMesh::compute_boundary_segments_"
2691  "connectivity_and_initial_zeta_values()",
2692  OOMPH_EXCEPTION_LOCATION);
2693  }
2694 #endif
2695 
2696  } // if (tmp_right_bulk_ele_pt->is_halo())
2697  else
2698  {
2699  // If not halo then state the info. to indicate that
2700  right_processor_plus_one[is] = 0;
2701  // Null this info.
2702  right_halo_element[is] = 0;
2703  // Null this info.
2704  right_haloed_element[is] = 0;
2705  }
2706 
2707  } // for (is < nsegments). Used to get the halo info. of the
2708  // segments
2709 
2710  // Now we have all the info. to be sent to the root processor and
2711  // compute the correct (global) boundary coordinates for the current
2712  // boundary
2713 
2714  // The root processor will be in charge of performing the computing
2715  // of the coordinate values along the boundary, all the other
2716  // processors only send their info. and wait for receiving the new
2717  // starting values for each of its segments
2718 
2719  // Choose the root processor
2720  const unsigned root_processor = 0;
2721  // ------------------------------------------------------------------
2722  // Starts the MPI stage
2723 
2724  // The root processor receives the number of segments of each
2725  // processor associated to the current boundary
2726  Vector<unsigned> root_nsegments_per_processor(nproc);
2727  unsigned nsegments_mpi = nsegments;
2728  MPI_Gather(&nsegments_mpi,
2729  1,
2730  MPI_UNSIGNED,
2731  &root_nsegments_per_processor[0],
2732  1,
2733  MPI_UNSIGNED,
2734  root_processor,
2735  comm_pt->mpi_comm());
2736 
2737  // Package the info. and prepare it to be sent
2738  // For the packaged info. we send 7 data per each segment, the indexes
2739  // are as follow; 0 left proc, 1 right proc, 2 left halo, 3 right
2740  // halo, 4 left haloed, 5 right haloed and 6 for nvertices per
2741  // segment
2742  // The size of the package (unsigned)
2743  const unsigned spu = 7;
2744  Vector<unsigned> flat_packed_unsigned_send_data(nsegments * spu);
2745  for (unsigned is = 0; is < nsegments; is++)
2746  {
2747  flat_packed_unsigned_send_data[(spu * is) + 0] =
2748  left_processor_plus_one[is];
2749  flat_packed_unsigned_send_data[(spu * is) + 1] =
2750  right_processor_plus_one[is];
2751  flat_packed_unsigned_send_data[(spu * is) + 2] = left_halo_element[is];
2752  flat_packed_unsigned_send_data[(spu * is) + 3] = right_halo_element[is];
2753  flat_packed_unsigned_send_data[(spu * is) + 4] = left_haloed_element[is];
2754  flat_packed_unsigned_send_data[(spu * is) + 5] = right_haloed_element[is];
2755  flat_packed_unsigned_send_data[(spu * is) + 6] =
2756  nvertices_per_segment[is];
2757  }
2758 
2759  // How many data will this processor send
2760  const unsigned nudata_to_send = flat_packed_unsigned_send_data.size();
2761 
2762  // How many data does the root processor will receive from each
2763  // processor
2764  Vector<int> root_nudata_to_receive(nproc, 0);
2765  // Total number of data to receive from all processors
2766  unsigned root_nutotal_data_receive = 0;
2767  for (unsigned ip = 0; ip < nproc; ip++)
2768  {
2769  // Compute the number of data the root processor will receive from
2770  // each processor
2771  root_nudata_to_receive[ip] = root_nsegments_per_processor[ip] * spu;
2772  // Add on the total number of data to receive
2773  root_nutotal_data_receive += root_nudata_to_receive[ip];
2774  }
2775 
2776  // Stores and compute the offsets (in root) for the data received
2777  // from each processor
2778  Vector<int> root_uoffsets_receive(nproc, 0);
2779  root_uoffsets_receive[0] = 0;
2780  for (unsigned ip = 1; ip < nproc; ip++)
2781  {
2782  // Compute the offset to store the values from each processor
2783  root_uoffsets_receive[ip] =
2784  root_uoffsets_receive[ip - 1] + root_nudata_to_receive[ip - 1];
2785  }
2786 
2787  // Create at least one entry so we don't get a seg fault below
2788  if (flat_packed_unsigned_send_data.size() == 0)
2789  {
2790  flat_packed_unsigned_send_data.resize(1);
2791  }
2792 
2793  // Vector where to receive the info.
2794  Vector<unsigned> flat_packed_unsigned_receive_data(
2795  root_nutotal_data_receive);
2796  if (my_rank != root_processor)
2797  {
2798  // Create at least one entry so we don't get a seg fault below
2799  if (flat_packed_unsigned_receive_data.size() == 0)
2800  {
2801  flat_packed_unsigned_receive_data.resize(1);
2802  }
2803  } // if (my_rank!=root_processor)
2804 
2805  MPI_Gatherv(&flat_packed_unsigned_send_data[0], // Flat package to
2806  // send info. from
2807  // each processor
2808  nudata_to_send, // Total number of data to send from
2809  // each processor
2810  MPI_UNSIGNED,
2811  &flat_packed_unsigned_receive_data[0], // Container
2812  // where to
2813  // receive the
2814  // info. from all
2815  // the processors
2816  &root_nudata_to_receive[0], // Number of data to receive
2817  // from each processor
2818  &root_uoffsets_receive[0], // The offset to store the
2819  // info. from each processor
2820  MPI_UNSIGNED,
2821  root_processor, // The processor that receives all the
2822  // info.
2823  comm_pt->mpi_comm());
2824 
2825  // Clear the flat package to send
2826  flat_packed_unsigned_send_data.clear();
2827  flat_packed_unsigned_send_data.resize(0);
2828 
2829  // Package the info. and prepare it to be sent
2830  // For the packaged info. we send 1 data per each segment which is
2831  // at the moment the arclength of each segment
2832  // The size of the package
2833  const unsigned spd = 1;
2834  Vector<double> flat_packed_double_send_data(nsegments * spd);
2835  for (unsigned is = 0; is < nsegments; is++)
2836  {
2837  flat_packed_double_send_data[(spd * is) + 0] = segment_arclength[is];
2838  }
2839 
2840  // How many data will this processor send
2841  const unsigned nddata_to_send = flat_packed_double_send_data.size();
2842  // How many data does the root processor will receive from each
2843  // processor
2844  Vector<int> root_nddata_to_receive(nproc, 0);
2845  // Total number of data to receive from all processors
2846  unsigned root_ndtotal_data_receive = 0;
2847  for (unsigned ip = 0; ip < nproc; ip++)
2848  {
2849  root_nddata_to_receive[ip] = root_nsegments_per_processor[ip] * spd;
2850  root_ndtotal_data_receive += root_nddata_to_receive[ip];
2851  }
2852 
2853  // Stores and compute the offsets for the data received from each
2854  // processor
2855  Vector<int> root_doffsets_receive(nproc, 0);
2856  root_doffsets_receive[0] = 0;
2857  for (unsigned ip = 1; ip < nproc; ip++)
2858  {
2859  // Compute the offset to store the values from each processor
2860  root_doffsets_receive[ip] =
2861  root_doffsets_receive[ip - 1] + root_nddata_to_receive[ip - 1];
2862  }
2863 
2864  // Create at least one entry so we don't get a seg fault below
2865  if (flat_packed_double_send_data.size() == 0)
2866  {
2867  flat_packed_double_send_data.resize(1);
2868  }
2869 
2870  // Vector where to receive the info.
2871  Vector<double> flat_packed_double_receive_data(root_ndtotal_data_receive);
2872  if (my_rank != root_processor)
2873  {
2874  // Create at least one entry so we don't get a seg fault below
2875  if (flat_packed_double_receive_data.size() == 0)
2876  {
2877  flat_packed_double_receive_data.resize(1);
2878  }
2879  }
2880 
2881  MPI_Gatherv(&flat_packed_double_send_data[0], // Flat package to
2882  // send info. from
2883  // each processor
2884  nddata_to_send, // Total number of data to send from
2885  // each processor
2886  MPI_DOUBLE,
2887  &flat_packed_double_receive_data[0], // Container where
2888  // to receive the
2889  // info. from all
2890  // the processors
2891  &root_nddata_to_receive[0], // Number of data to receive
2892  // from each processor
2893  &root_doffsets_receive[0], // The offset to store the
2894  // info. from each processor
2895  MPI_DOUBLE,
2896  root_processor, // The processor that receives all the
2897  // info.
2898  comm_pt->mpi_comm());
2899 
2900  // Clear the flat package to send
2901  flat_packed_double_send_data.clear();
2902  flat_packed_double_send_data.resize(0);
2903 
2904  // The next three containers are only used by the root processor at
2905  // the end of its computations but it is necessary that all the
2906  // processors know them when calling back the info.
2907 
2908  // Container that state the initial arclength for each segments
2909  // of each processor
2910  Vector<Vector<double>> root_initial_segment_arclength(nproc);
2911 
2912  // Container that state the number of vertices before each segment
2913  // in a given processor
2914  Vector<Vector<unsigned>> root_nvertices_before_segment(nproc);
2915 
2916  // The root processor needs to tell the other processor if it was
2917  // necessary to reverse a segment. Each processor should therefore
2918  // invert the face elements that compose every segment that was
2919  // inverted by the root processor
2920  Vector<Vector<unsigned>> root_segment_inverted(nproc);
2921 
2922  // Used to store the accumulated arclength, used at the end of
2923  // communications to store the total arclength
2924  double root_accumulated_arclength = 0.0;
2925 
2926  // Store the accumulated number of vertices, it means the total number
2927  // of vertices before each segment (counter)
2928  unsigned root_accumulated_vertices_before_segment = 0;
2929 
2930  // The root processor is in charge of performing the connections
2931  // of the segments that define the complete boundary
2932  if (my_rank == root_processor)
2933  {
2934  // From the flat packaged received data re-create the data
2935  // structures storing the info. regarding the connectivity of the
2936  // segments, the number of vertices per segment and the local
2937  // arclength of each segment
2938 
2939  // Stores the "rank" of the processor to the left of each segment,
2940  // zero if there is no processor to the left which states that the
2941  // segment is the first one on the boundary
2942  Vector<Vector<unsigned>> root_left_processor_plus_one(nproc);
2943 
2944  // Stores the "rank" of the processor to the right of each segment,
2945  // zero if there is no processor to the right which states that the
2946  // segment is the last one on the boundary
2947  Vector<Vector<unsigned>> root_right_processor_plus_one(nproc);
2948 
2949  // The id. of the halo element to the left of the segment, note that
2950  // this info. is not necessary if there is no processor to the left
2951  // of the segment or if the processor has no info about the boundary
2952  Vector<Vector<unsigned>> root_left_halo_element(nproc);
2953 
2954  // The id. of the halo element to the right of the segment, note
2955  // that this info. is not necessary if there is no processor to
2956  // the right of the segment or if the processor has no info about
2957  // the boundary
2958  Vector<Vector<unsigned>> root_right_halo_element(nproc);
2959 
2960  // The id. of the haloed element to the left of the segment, note
2961  // that this info. is not necessary if there is no processor to
2962  // the left of the segment or if the processor has no info about
2963  // the boundary
2964  Vector<Vector<unsigned>> root_left_haloed_element(nproc);
2965 
2966  // The id. of the haloed element to the right of the segment, note
2967  // that this info. is not necessary if there is no processor to the
2968  // right of the segment or if the processor has no info about the
2969  // boundary
2970  Vector<Vector<unsigned>> root_right_haloed_element(nproc);
2971 
2972  // The number of vertices per segment in each processor
2973  Vector<Vector<unsigned>> root_nvertices_per_segment(nproc);
2974 
2975  // The arclength of each of the segments in the processors
2976  Vector<Vector<double>> root_segment_arclength(nproc);
2977 
2978  unsigned ucounter = 0;
2979  unsigned dcounter = 0;
2980  for (unsigned ip = 0; ip < nproc; ip++)
2981  {
2982  // Get the number of segments in the current processor
2983  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
2984 
2985  root_left_processor_plus_one[ip].resize(nsegs_iproc);
2986  root_right_processor_plus_one[ip].resize(nsegs_iproc);
2987  root_left_halo_element[ip].resize(nsegs_iproc);
2988  root_right_halo_element[ip].resize(nsegs_iproc);
2989  root_left_haloed_element[ip].resize(nsegs_iproc);
2990  root_right_haloed_element[ip].resize(nsegs_iproc);
2991 
2992  // Additional info.
2993  root_nvertices_per_segment[ip].resize(nsegs_iproc);
2994  root_segment_arclength[ip].resize(nsegs_iproc);
2995  root_segment_inverted[ip].resize(nsegs_iproc);
2996 
2997  // Extract the info. from the BIG package received from all
2998  // processors
2999  for (unsigned is = 0; is < nsegs_iproc; is++)
3000  {
3001  // ------ The flat unsigned package ------
3002  root_left_processor_plus_one[ip][is] =
3003  flat_packed_unsigned_receive_data[ucounter++];
3004  root_right_processor_plus_one[ip][is] =
3005  flat_packed_unsigned_receive_data[ucounter++];
3006  root_left_halo_element[ip][is] =
3007  flat_packed_unsigned_receive_data[ucounter++];
3008  root_right_halo_element[ip][is] =
3009  flat_packed_unsigned_receive_data[ucounter++];
3010  root_left_haloed_element[ip][is] =
3011  flat_packed_unsigned_receive_data[ucounter++];
3012  root_right_haloed_element[ip][is] =
3013  flat_packed_unsigned_receive_data[ucounter++];
3014  root_nvertices_per_segment[ip][is] =
3015  flat_packed_unsigned_receive_data[ucounter++];
3016 
3017  // ------ The flat double package ------
3018  root_segment_arclength[ip][is] =
3019  flat_packed_double_receive_data[dcounter++];
3020  } // for (is < nsegs_iproc)
3021  } // for (ip < nproc)
3022 
3023  // Now the root processor has all the info. to find out the
3024  // CONNECTIVITY of the segments in each processor
3025 
3026  // Container that stores the info. related with the connectivity
3027  // of the segments of each processor
3028  Vector<Vector<int>> left_connected_segment_plus_one(nproc);
3029  Vector<Vector<int>> right_connected_segment_plus_one(nproc);
3030  for (unsigned ip = 0; ip < nproc; ip++)
3031  {
3032  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3033  left_connected_segment_plus_one[ip].resize(nsegs_iproc, -1);
3034  right_connected_segment_plus_one[ip].resize(nsegs_iproc, -1);
3035  } // for (ip < nprocs)
3036 
3037  // In charge of storing the connectivity of the segments, the pair
3038  // indicates the processor and the segment number
3039  std::list<std::pair<unsigned, unsigned>> proc_seg_connectivity;
3040  proc_seg_connectivity.clear();
3041 
3042  // Done segments on processor
3043  std::map<std::pair<unsigned, unsigned>, bool> done_segment;
3044 
3045  // Take the first segment of the first processor with segments and
3046  // add it to the list of segments
3047  unsigned left_proc = 0;
3048  unsigned right_proc = 0;
3049  unsigned left_seg = 0;
3050  unsigned right_seg = 0;
3051  for (unsigned ip = 0; ip < nproc; ip++)
3052  {
3053  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3054  if (nsegs_iproc > 0)
3055  {
3056  right_proc = left_proc = ip;
3057  right_seg = left_seg = 0;
3058  break; // Break because it is the first processor with at
3059  // least one segment
3060  }
3061  } // for (ip < nproc)
3062 
3063  // ... and add it to the list of segments
3064  std::pair<unsigned, unsigned> add_segment =
3065  std::make_pair(left_proc, left_seg);
3066  done_segment[add_segment] = true;
3067  proc_seg_connectivity.push_back(add_segment);
3068 
3069  // Flags to indicate when a segment was added to the left or right
3070  // of the current list of segments
3071  bool added_segment_to_the_left = false;
3072  bool added_segment_to_the_right = false;
3073 
3074  do // while(added_segment_to_the_left || added_segment_to_the_right)
3075  {
3076  // Read the left-most processor and segment in the list
3077  std::pair<unsigned, unsigned> left_pair = proc_seg_connectivity.front();
3078  left_proc = left_pair.first;
3079  left_seg = left_pair.second;
3080 
3081  // Get the processor number to the left of the left-most
3082  // segment in the list
3083  const unsigned new_left_proc =
3084  root_left_processor_plus_one[left_proc][left_seg];
3085 
3086  if (new_left_proc != 0)
3087  {
3088  // Initialise flag
3089  added_segment_to_the_left = false;
3090  // Get the left halo element id
3091  const unsigned left_halo_id =
3092  root_left_halo_element[left_proc][left_seg];
3093 
3094  // Get the left haloed element id
3095  const unsigned left_haloed_id =
3096  root_left_haloed_element[left_proc][left_seg];
3097 
3098  // Go through the segments on the new left processor and look
3099  // for the corresponding left_halo_id in the haloed_ids
3100  const unsigned nsegs_new_left_proc =
3101  root_nsegments_per_processor[new_left_proc - 1];
3102 
3103  for (unsigned ils = 0; ils < nsegs_new_left_proc; ils++)
3104  {
3105  std::pair<unsigned, unsigned> candidate_seg =
3106  std::make_pair(new_left_proc - 1, ils);
3107 
3108  // Check that the segment has not been already added
3109  if (!done_segment[candidate_seg])
3110  {
3111  // Only consider the segments on new left processor which
3112  // right processor is the current one (left_proc)
3113  const unsigned right_proc_of_new_left_proc =
3114  root_right_processor_plus_one[new_left_proc - 1][ils];
3115  // Also get the left_proc_of_new_left_proc (in case that it
3116  // be necessary to invert the segment)
3117  const unsigned left_proc_of_new_left_proc =
3118  root_left_processor_plus_one[new_left_proc - 1][ils];
3119  // Check the not inverted case (to the left and not
3120  // inverted)
3121  if (right_proc_of_new_left_proc != 0 &&
3122  right_proc_of_new_left_proc - 1 == left_proc)
3123  {
3124  // Get the haloed/haloed element id of the current segment
3125  // in the new left processor and compare it to the
3126  // halo/haloed element id of the left_processor
3127  const unsigned right_halo_id =
3128  root_right_halo_element[new_left_proc - 1][ils];
3129  const unsigned right_haloed_id =
3130  root_right_haloed_element[new_left_proc - 1][ils];
3131  if (left_halo_id == right_haloed_id &&
3132  left_haloed_id == right_halo_id)
3133  {
3134  // We have a match of the segments (store the segment
3135  // number plus one on the processor to the left)
3136  left_connected_segment_plus_one[left_proc][left_seg] =
3137  ils + 1;
3138  // Add the pair to the connectivity list
3139  proc_seg_connectivity.push_front(candidate_seg);
3140  added_segment_to_the_left = true;
3141  break;
3142  }
3143  } // if (right_proc_of_new_left_proc-1 == left_proc)
3144 
3145  // Check the inverted case (to the left and inverted)
3146  if (left_proc_of_new_left_proc != 0 &&
3147  left_proc_of_new_left_proc - 1 == left_proc)
3148  {
3149  // Get the haloed element id of the current segment
3150  // (inverted version) in the new left processor and
3151  // compare it to the halo element id of the left_processor
3152  const unsigned inv_left_halo_id =
3153  root_left_halo_element[new_left_proc - 1][ils];
3154  const unsigned inv_left_haloed_id =
3155  root_left_haloed_element[new_left_proc - 1][ils];
3156  if (left_halo_id == inv_left_haloed_id &&
3157  left_haloed_id == inv_left_halo_id)
3158  {
3159  // We have a match of the segments (store the segment
3160  // number plus one on the processor to the left)
3161  left_connected_segment_plus_one[left_proc][left_seg] =
3162  ils + 1;
3163  // Add the pair to the connectivity list
3164  proc_seg_connectivity.push_front(candidate_seg);
3165 
3166  // In addition to the connectivity we need to invert the
3167  // segment (the information)
3168  const unsigned tmp_proc =
3169  root_left_processor_plus_one[new_left_proc - 1][ils];
3170  const unsigned tmp_halo =
3171  root_left_halo_element[new_left_proc - 1][ils];
3172  const unsigned tmp_haloed =
3173  root_left_haloed_element[new_left_proc - 1][ils];
3174 
3175  root_left_processor_plus_one[new_left_proc - 1][ils] =
3176  root_right_processor_plus_one[new_left_proc - 1][ils];
3177  root_left_halo_element[new_left_proc - 1][ils] =
3178  root_right_halo_element[new_left_proc - 1][ils];
3179  root_left_haloed_element[new_left_proc - 1][ils] =
3180  root_right_haloed_element[new_left_proc - 1][ils];
3181 
3182  root_right_processor_plus_one[new_left_proc - 1][ils] =
3183  tmp_proc;
3184  root_right_halo_element[new_left_proc - 1][ils] = tmp_halo;
3185  root_right_haloed_element[new_left_proc - 1][ils] =
3186  tmp_haloed;
3187 
3188  // ... and mark the segment as inverted in the root
3189  // processor to inform back to the owner processor
3190  root_segment_inverted[new_left_proc - 1][ils] = 1;
3191 
3192  added_segment_to_the_left = true;
3193  break;
3194  }
3195  } // if (left_proc_of_new_left_proc-1 == left_proc)
3196  } // if (!done_segment[candidate_segment])
3197  } // for (ils < nsegs_new_left_proc)
3198 
3199 #ifdef PARANOID
3200  if (!added_segment_to_the_left)
3201  {
3202  std::ostringstream error_message;
3203  error_message
3204  << "The corresponding processor and segment to the left of "
3205  << "the current left\nmost segment was not found\n";
3206  throw OomphLibError(error_message.str(),
3207  "TriangleMesh::compute_boundary_segments_"
3208  "connectivity_and_initial_zeta_values()",
3209  OOMPH_EXCEPTION_LOCATION);
3210  }
3211 #endif
3212  } // if (new_left_proc != 0)
3213  else
3214  {
3215  // No more segments to the left
3216  added_segment_to_the_left = false;
3217  }
3218 
3219  // Read the info. of the right processor and the right segment
3220  std::pair<unsigned, unsigned> right_pair = proc_seg_connectivity.back();
3221  right_proc = right_pair.first;
3222  right_seg = right_pair.second;
3223 
3224  // Get the processor number to the right of the right-most
3225  // segment in the list
3226  const unsigned new_right_proc =
3227  root_right_processor_plus_one[right_proc][right_seg];
3228 
3229  if (new_right_proc != 0)
3230  {
3231  // Initialise flag
3232  added_segment_to_the_right = false;
3233  // Get the right halo element id
3234  const unsigned right_halo_id =
3235  root_right_halo_element[right_proc][right_seg];
3236 
3237  // Get the right halo element id
3238  const unsigned right_haloed_id =
3239  root_right_haloed_element[right_proc][right_seg];
3240 
3241  // Go through the segments on the new right processor and look
3242  // for the corresponding right_halo_id in the haloed_ids
3243  const unsigned nsegs_new_right_proc =
3244  root_nsegments_per_processor[new_right_proc - 1];
3245 
3246  for (unsigned irs = 0; irs < nsegs_new_right_proc; irs++)
3247  {
3248  std::pair<unsigned, unsigned> candidate_seg =
3249  std::make_pair(new_right_proc - 1, irs);
3250 
3251  // Check that the segment has not been already added
3252  if (!done_segment[candidate_seg])
3253  {
3254  // Only consider the segments on new right processor which
3255  // left processor is the current one (right_proc)
3256  const unsigned left_proc_of_new_right_proc =
3257  root_left_processor_plus_one[new_right_proc - 1][irs];
3258  // Also get the right_proc_of_new_right_proc (in case
3259  // that it be necessary to invert the segment)
3260  const unsigned right_proc_of_new_right_proc =
3261  root_right_processor_plus_one[new_right_proc - 1][irs];
3262  // Check the not inverted case (to the right and not
3263  // inverted)
3264  if (left_proc_of_new_right_proc != 0 &&
3265  left_proc_of_new_right_proc - 1 == right_proc)
3266  {
3267  // Get the haloed element id of the current segment in the
3268  // new right processor and compare it to the halo element
3269  // id of the right_processor
3270  const unsigned left_halo_id =
3271  root_left_halo_element[new_right_proc - 1][irs];
3272  const unsigned left_haloed_id =
3273  root_left_haloed_element[new_right_proc - 1][irs];
3274 
3275  if (right_halo_id == left_haloed_id &&
3276  right_haloed_id == left_halo_id)
3277  {
3278  // We have a match of the segments (store the segment
3279  // number plus one on the processor to the right)
3280  right_connected_segment_plus_one[right_proc][right_seg] =
3281  irs + 1;
3282  // Add the connectivity information to the list
3283  proc_seg_connectivity.push_back(candidate_seg);
3284  added_segment_to_the_right = true;
3285  break;
3286  }
3287  } // if (left_proc_of_new_right_proc-1 == right_proc)
3288 
3289  // Check the inverted case (to the right and inverted)
3290  if (right_proc_of_new_right_proc != 0 &&
3291  right_proc_of_new_right_proc - 1 == right_proc)
3292  {
3293  // Get the haloed element id of the current segment
3294  // (inverted version) in the new right processor and
3295  // compare it to the halo element id of the
3296  // right_processor
3297  const unsigned inv_right_halo_id =
3298  root_right_halo_element[new_right_proc - 1][irs];
3299  const unsigned inv_right_haloed_id =
3300  root_right_haloed_element[new_right_proc - 1][irs];
3301  if (right_halo_id == inv_right_haloed_id &&
3302  right_haloed_id == inv_right_halo_id)
3303  {
3304  // We have a match of the segments (store the segment
3305  // number plus one on the processor to the right)
3306  right_connected_segment_plus_one[right_proc][right_seg] =
3307  irs + 1;
3308  // Add the connectivity information to the list
3309  proc_seg_connectivity.push_back(candidate_seg);
3310  // In addition to the connectivity we need to invert the
3311  // segment
3312  const unsigned tmp_proc =
3313  root_left_processor_plus_one[new_right_proc - 1][irs];
3314  const unsigned tmp_halo =
3315  root_left_halo_element[new_right_proc - 1][irs];
3316  const unsigned tmp_haloed =
3317  root_left_haloed_element[new_right_proc - 1][irs];
3318 
3319  root_left_processor_plus_one[new_right_proc - 1][irs] =
3320  root_right_processor_plus_one[new_right_proc - 1][irs];
3321  root_left_halo_element[new_right_proc - 1][irs] =
3322  root_right_halo_element[new_right_proc - 1][irs];
3323  root_left_haloed_element[new_right_proc - 1][irs] =
3324  root_right_haloed_element[new_right_proc - 1][irs];
3325 
3326  root_right_processor_plus_one[new_right_proc - 1][irs] =
3327  tmp_proc;
3328  root_right_halo_element[new_right_proc - 1][irs] = tmp_halo;
3329  root_right_haloed_element[new_right_proc - 1][irs] =
3330  tmp_haloed;
3331 
3332  // ... and mark the segment as inverted in the root
3333  // processor to inform back to the owner processor
3334  root_segment_inverted[new_right_proc - 1][irs] = 1;
3335 
3336  added_segment_to_the_right = true;
3337  break;
3338  }
3339  } // if (right_proc_of_new_right_proc-1 == right_proc)
3340  } // if (!done_segment[candidate_segment])
3341  } // for (irs < nsegs_new_left_proc)
3342 
3343 #ifdef PARANOID
3344  if (!added_segment_to_the_right)
3345  {
3346  std::ostringstream error_message;
3347  error_message
3348  << "The corresponding processor and segment to the right of "
3349  << "the current right\nmost segment was not found\n";
3350  throw OomphLibError(error_message.str(),
3351  "TriangleMesh::compute_boundary_segments_"
3352  "connectivity_and_initial_zeta_values()",
3353  OOMPH_EXCEPTION_LOCATION);
3354  }
3355 #endif
3356  } // if (new_right_proc != 0)
3357  else
3358  {
3359  // No more segments to the left
3360  added_segment_to_the_right = false;
3361  }
3362 
3363  } while (added_segment_to_the_left || added_segment_to_the_right);
3364 
3365  // Once we have connected the segments then we can compute the
3366  // initial and final zeta values based on the arclength of each
3367  // individual segment
3368 
3369  // Get the total number of segments, which MUST be the same as the
3370  // total number of segments in all processors
3371  const unsigned ntotal_segments = proc_seg_connectivity.size();
3372 #ifdef PARANOID
3373  unsigned tmp_total_segments = 0;
3374  for (unsigned ip = 0; ip < nproc; ip++)
3375  {
3376  tmp_total_segments += root_nsegments_per_processor[ip];
3377  }
3378 
3379  // Check that the total number of segments in all processors is
3380  // the same as the number of segments that form the boundary
3381  if (ntotal_segments != tmp_total_segments)
3382  {
3383  std::ostringstream error_message;
3384  error_message << "The number of sorted segments (" << ntotal_segments
3385  << ") on "
3386  << "boundary (" << b
3387  << ")\nis different from the total number of "
3388  << "segments (" << tmp_total_segments
3389  << ") in all\nprocessors.\n\n";
3390  throw OomphLibError(error_message.str(),
3391  OOMPH_CURRENT_FUNCTION,
3392  OOMPH_EXCEPTION_LOCATION);
3393  } // if (ntotal_segments!=tmp_total_segments)
3394 #endif
3395 
3396  // Now that we know the connectivity of the segments we can
3397  // compute the initial arclength of each segment in the
3398  // processors. Additionally we also get the number of vertices
3399  // before each of the segments. Resize the containers considering
3400  // the number of segments in each processor
3401  for (unsigned ip = 0; ip < nproc; ip++)
3402  {
3403  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3404  root_initial_segment_arclength[ip].resize(nsegs_iproc);
3405  root_nvertices_before_segment[ip].resize(nsegs_iproc);
3406  }
3407 
3408  Vector<double> aux_initial_segment_arclength(ntotal_segments);
3409  Vector<unsigned> aux_nvertices_before_segment(ntotal_segments);
3410 
3411  ucounter = 0;
3412  for (std::list<std::pair<unsigned, unsigned>>::iterator it_list =
3413  proc_seg_connectivity.begin();
3414  it_list != proc_seg_connectivity.end();
3415  it_list++)
3416  {
3417  const unsigned iproc = static_cast<unsigned>((*it_list).first);
3418  const unsigned iseg = static_cast<unsigned>((*it_list).second);
3419  const double iseg_arclength = root_segment_arclength[iproc][iseg];
3420  const unsigned iseg_nvertices = root_nvertices_per_segment[iproc][iseg];
3421 
3422  aux_initial_segment_arclength[ucounter] = root_accumulated_arclength;
3423  aux_nvertices_before_segment[ucounter] =
3424  root_accumulated_vertices_before_segment;
3425 
3426  // Set the initial zeta value for the segment
3427  root_initial_segment_arclength[iproc][iseg] =
3428  root_accumulated_arclength;
3429  // Set the number of vertices before the current segment
3430  root_nvertices_before_segment[iproc][iseg] =
3431  root_accumulated_vertices_before_segment;
3432 
3433  // Add the arclength of the segment to the global arclength
3434  root_accumulated_arclength += iseg_arclength;
3435  // Add the number of vertices to the global number of vertices
3436  root_accumulated_vertices_before_segment += iseg_nvertices - 1;
3437 
3438  // Increase the counter
3439  ucounter++;
3440  } // for (loop over the sorted segments to assigne initial
3441  // arlength and initial number of vertices)
3442 
3443  // Increase by one to get the total number of vertices on the
3444  // boundary
3445  root_accumulated_vertices_before_segment++;
3446 
3447  // Get the processors with the initial and final segment.
3448  proc_with_initial_seg = proc_seg_connectivity.front().first;
3449  proc_with_final_seg = proc_seg_connectivity.back().first;
3450  // Also get the corresponding initial and final segment indexes
3451  // (on the initial and final processors)
3452  initial_segment = proc_seg_connectivity.front().second;
3453  final_segment = proc_seg_connectivity.back().second;
3454 
3455  } // if (my_rank == root_processor)
3456 
3457  // Get the total number of segments
3458  unsigned root_ntotal_segments = 0;
3459  for (unsigned ip = 0; ip < nproc; ip++)
3460  {
3461  root_ntotal_segments += root_nsegments_per_processor[ip];
3462  }
3463 
3464  // Package the info. that will be sent to each processor. For the
3465  // unsigned package we send the number of vertices before each
3466  // segment in each processor and whether it was inverted or not
3467  // Package size
3468  const unsigned rspu = 2;
3469  flat_packed_unsigned_send_data.clear();
3470  flat_packed_unsigned_send_data.resize(root_ntotal_segments * rspu);
3471  unsigned ucounter = 0;
3472  // Collect the info. from all the segments in the processors
3473  for (unsigned ip = 0; ip < nproc; ip++)
3474  {
3475  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3476  for (unsigned is = 0; is < nsegs_iproc; is++)
3477  {
3478  flat_packed_unsigned_send_data[ucounter++] =
3479  root_nvertices_before_segment[ip][is];
3480  flat_packed_unsigned_send_data[ucounter++] =
3481  root_segment_inverted[ip][is];
3482  } // for (is < nsegs_iproc)
3483  } // for (ip < nproc)
3484 
3485  // How many data does the root processor will send to each processor
3486  Vector<int> root_nudata_to_send(nproc, 0);
3487  for (unsigned ip = 0; ip < nproc; ip++)
3488  {
3489  // Get the number of data to send to ip processor
3490  root_nudata_to_send[ip] = root_nsegments_per_processor[ip] * rspu;
3491  }
3492 
3493  // Store and compute the offsets for the data sent to each processor
3494  Vector<int> root_uoffsets_send(nproc, 0);
3495  root_uoffsets_send[0] = 0;
3496  for (unsigned ip = 1; ip < nproc; ip++)
3497  {
3498  // Compute the offset to send the values to each processor
3499  root_uoffsets_send[ip] =
3500  root_uoffsets_send[ip - 1] + root_nudata_to_send[ip - 1];
3501  }
3502 
3503  // Number of data to receive from root
3504  unsigned nutotal_data_receive = nsegments * rspu;
3505 
3506  if (my_rank != root_processor)
3507  {
3508  // Create at least one entry so we don't get a seg fault below
3509  if (flat_packed_unsigned_send_data.size() == 0)
3510  {
3511  flat_packed_unsigned_send_data.resize(1);
3512  }
3513  }
3514 
3515  // Clear and resize the vector where to receive the info.
3516  flat_packed_unsigned_receive_data.clear();
3517  flat_packed_unsigned_receive_data.resize(nutotal_data_receive);
3518  // Create at least one entry so we don't get a seg fault below
3519  if (flat_packed_unsigned_receive_data.size() == 0)
3520  {
3521  flat_packed_unsigned_receive_data.resize(1);
3522  }
3523 
3524  MPI_Scatterv(&flat_packed_unsigned_send_data[0],
3525  &root_nudata_to_send[0],
3526  &root_uoffsets_send[0],
3527  MPI_UNSIGNED,
3528  &flat_packed_unsigned_receive_data[0],
3529  nutotal_data_receive,
3530  MPI_UNSIGNED,
3531  root_processor,
3532  comm_pt->mpi_comm());
3533 
3534  // Package the info. that will be sent to each processor, for the
3535  // double package we send (one data per segment) the initial
3536  // arclength for each segment
3537  const unsigned rspd = 1;
3538  flat_packed_double_send_data.clear();
3539  flat_packed_double_send_data.resize(root_ntotal_segments * rspd);
3540  unsigned dcounter = 0;
3541  // Collect the info. from all the segments in the processors
3542  for (unsigned ip = 0; ip < nproc; ip++)
3543  {
3544  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3545  for (unsigned is = 0; is < nsegs_iproc; is++)
3546  {
3547  flat_packed_double_send_data[dcounter++] =
3548  root_initial_segment_arclength[ip][is];
3549  }
3550  }
3551 
3552  // How many data does the root processor will send to each processor
3553  Vector<int> root_nddata_to_send(nproc, 0);
3554  for (unsigned ip = 0; ip < nproc; ip++)
3555  {
3556  // Number of data send to ip processor
3557  root_nddata_to_send[ip] = root_nsegments_per_processor[ip] * rspd;
3558  }
3559 
3560  // Store and compute the offsets for the data sent to each processor
3561  Vector<int> root_doffsets_send(nproc, 0);
3562  root_doffsets_send[0] = 0;
3563  for (unsigned ip = 1; ip < nproc; ip++)
3564  {
3565  // Compute the offset to send the values to each processor
3566  root_doffsets_send[ip] =
3567  root_doffsets_send[ip - 1] + root_nddata_to_send[ip - 1];
3568  }
3569 
3570  // Number of double data to receive from root
3571  unsigned ndtotal_data_receive = nsegments * rspd;
3572 
3573  if (my_rank != root_processor)
3574  {
3575  // Create at least one entry so we don't get a seg fault below
3576  if (flat_packed_double_send_data.size() == 0)
3577  {
3578  flat_packed_double_send_data.resize(1);
3579  }
3580  }
3581 
3582  // Clear and resize the vector where to receive the info.
3583  flat_packed_double_receive_data.clear();
3584  flat_packed_double_receive_data.resize(ndtotal_data_receive);
3585  // Create at least one entry so we don't get a seg fault below
3586  if (flat_packed_double_receive_data.size() == 0)
3587  {
3588  flat_packed_double_receive_data.resize(1);
3589  }
3590 
3591  MPI_Scatterv(&flat_packed_double_send_data[0],
3592  &root_nddata_to_send[0],
3593  &root_doffsets_send[0],
3594  MPI_DOUBLE,
3595  &flat_packed_double_receive_data[0],
3596  ndtotal_data_receive,
3597  MPI_DOUBLE,
3598  root_processor,
3599  comm_pt->mpi_comm());
3600 
3601  // Read if the segments need to be inverted and read the initial
3602  // arclengths
3603  ucounter = 0;
3604  dcounter = 0;
3605 
3606  // Read the info. from the flat package and store it in their
3607  // corresponding containers
3608  for (unsigned is = 0; is < nsegments; is++)
3609  {
3610  // The flat unsigned package
3611  nvertices_before_segment[is] =
3612  flat_packed_unsigned_receive_data[ucounter++];
3613  // The segment inverted flag
3614  segment_inverted[is] = flat_packed_unsigned_receive_data[ucounter++];
3615  // The flat double package
3616  initial_segment_arclength[is] =
3617  flat_packed_double_receive_data[dcounter++];
3618  } // for (is < nsegments)
3619 
3620  // Perform two additional communications to get the total number of
3621  // vertices, the processors with the initial and final segments, the
3622  // corresponding initial and final segments ...
3623  const unsigned numore_info = 5;
3624  Vector<unsigned> flat_package_unsigned_more_info(numore_info);
3625  // Prepare the info ...
3626  flat_package_unsigned_more_info[0] =
3627  root_accumulated_vertices_before_segment;
3628  flat_package_unsigned_more_info[1] = proc_with_initial_seg;
3629  flat_package_unsigned_more_info[2] = proc_with_final_seg;
3630  flat_package_unsigned_more_info[3] = initial_segment;
3631  flat_package_unsigned_more_info[4] = final_segment;
3632 
3633  // Send the info. to all processors
3634  MPI_Bcast(&flat_package_unsigned_more_info[0],
3635  numore_info,
3636  MPI_UNSIGNED,
3637  root_processor,
3638  comm_pt->mpi_comm());
3639 
3640  // ... and store the info. in the proper containers
3641  root_accumulated_vertices_before_segment =
3642  flat_package_unsigned_more_info[0];
3643  proc_with_initial_seg = flat_package_unsigned_more_info[1];
3644  proc_with_final_seg = flat_package_unsigned_more_info[2];
3645  initial_segment = flat_package_unsigned_more_info[3];
3646  final_segment = flat_package_unsigned_more_info[4];
3647 
3648  // Do the same for the maximum zeta value
3649  MPI_Bcast(&root_accumulated_arclength,
3650  1,
3651  MPI_DOUBLE,
3652  root_processor,
3653  comm_pt->mpi_comm());
3654 
3655  // -----------------------------------------------------------------
3656  // Clear the storage to store the data that will be used by the
3657  // setup boundary coordinates method, if we do not perform the
3658  // cleaning then previous data from previous iterations will remain
3659  // there
3660  // -----------------------------------------------------------------
3661  // The info. for the boundary
3662  Boundary_initial_coordinate[b].clear();
3663  Boundary_final_coordinate[b].clear();
3664 
3665  Boundary_initial_zeta_coordinate[b].clear();
3666  Boundary_final_zeta_coordinate[b].clear();
3667 
3668  // The info. for the segments
3669  Boundary_segment_inverted[b].clear();
3670  Boundary_segment_initial_coordinate[b].clear();
3671  Boundary_segment_final_coordinate[b].clear();
3672 
3673  Boundary_segment_initial_zeta[b].clear();
3674  Boundary_segment_final_zeta[b].clear();
3675 
3676  Boundary_segment_initial_arclength[b].clear();
3677  Boundary_segment_final_arclength[b].clear();
3678 
3679  // Now copy all the info. to the containers to be sent to any other
3680  // mesh (in the adaptation method)
3681  for (unsigned is = 0; is < nsegments; is++)
3682  {
3683  // At this point we can get the initial and final coordinates for
3684  // each segment
3685  Vector<double> first_seg_coord(2);
3686  Vector<double> last_seg_coord(2);
3687 
3688  // In order to get the first and last coordinates of each segment we
3689  // first need to identify the first and last nonhalo element of each
3690  // segment, and then get the first and last node of the segment
3691 
3692  // Get the first nonhalo face element on the segment
3693  FiniteElement* first_seg_ele_pt =
3694  segment_sorted_nonhalo_ele_pt[is].front();
3695 
3696 #ifdef PARANOID
3697  // Check if the face element is nonhalo, it shouldn't, but better
3698  // check
3699  if (first_seg_ele_pt->is_halo())
3700  {
3701  std::ostringstream error_message;
3702  error_message << "The first face element in the (" << is
3703  << ")-th segment is halo\n";
3704  throw OomphLibError(error_message.str(),
3705  "TriangleMesh::compute_boundary_segments_"
3706  "connectivity_and_initial_zeta_values()",
3707  OOMPH_EXCEPTION_LOCATION);
3708  } // if (tmp_first_bulk_ele_pt->is_halo())
3709 #endif
3710 
3711  // Number of nodes
3712  const unsigned nnod = first_seg_ele_pt->nnode();
3713 
3714  // Get the first node of the current segment
3715  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
3716  if (is_inverted[first_seg_ele_pt])
3717  {
3718  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod - 1);
3719  }
3720 
3721  // Get the last nonhalo face element on the segment
3722  FiniteElement* last_seg_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
3723 
3724 #ifdef PARANOID
3725  // Check if the face element is nonhalo, it shouldn't, but better
3726  // check
3727  if (last_seg_ele_pt->is_halo())
3728  {
3729  std::ostringstream error_message;
3730  error_message << "The last face element in the (" << is
3731  << ")-th segment is halo\n";
3732  throw OomphLibError(error_message.str(),
3733  "TriangleMesh::compute_boundary_segments_"
3734  "connectivity_and_initial_zeta_values()",
3735  OOMPH_EXCEPTION_LOCATION);
3736  } // if (tmp_first_bulk_ele_pt->is_halo())
3737 #endif
3738 
3739  // Get the last node of the current segment
3740  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod - 1);
3741  if (is_inverted[last_seg_ele_pt])
3742  {
3743  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
3744  }
3745 
3746  // Get the coordinates for the first and last segment's node
3747  for (unsigned i = 0; i < 2; i++)
3748  {
3749  first_seg_coord[i] = first_seg_node_pt->x(i);
3750  last_seg_coord[i] = last_seg_node_pt->x(i);
3751  }
3752 
3753  // -----------------------------------------------------------------
3754  // Copy the info. if the segment is inverted
3755  Boundary_segment_inverted[b].push_back(segment_inverted[is]);
3756 
3757  // Check if the segment is inverted, if that is the case then invert
3758  // the first and last seg. coordinates
3759  if (!segment_inverted[is])
3760  {
3761  // Store the initial and final coordinates that will help to
3762  // identify the segments in the new meshes created from this one
3763  Boundary_segment_initial_coordinate[b].push_back(first_seg_coord);
3764  Boundary_segment_final_coordinate[b].push_back(last_seg_coord);
3765  }
3766  else
3767  {
3768  // Store the initial and final coordinates that will help to
3769  // identify the segments in the new meshes created from this one
3770  // Invert the initial and final coordinates
3771  Boundary_segment_initial_coordinate[b].push_back(last_seg_coord);
3772  Boundary_segment_final_coordinate[b].push_back(first_seg_coord);
3773  }
3774 
3775  // Now assign initial and final zeta boundary coordinates for each
3776  // segment
3777  // -----------------------------------------------------------------
3778  // If there is a geom object then
3779  if (boundary_geom_object_pt(b) != 0)
3780  {
3781  // Store the initial and final zeta for the current segments (we
3782  // got this when we assigned arclength to the segments in the
3783  // current processor)
3784  if (segment_inverted[is])
3785  {
3786  Boundary_segment_initial_zeta[b].push_back(final_zeta_segment[is]);
3787  Boundary_segment_final_zeta[b].push_back(initial_zeta_segment[is]);
3788  }
3789  else
3790  {
3791  Boundary_segment_initial_zeta[b].push_back(initial_zeta_segment[is]);
3792  Boundary_segment_final_zeta[b].push_back(final_zeta_segment[is]);
3793  }
3794  } // if (boundary_geom_object_pt(b)!=0)
3795  else
3796  {
3797  // Store the initial arclength and vertices number for the
3798  // current segment
3799  Boundary_segment_initial_arclength[b].push_back(
3800  initial_segment_arclength[is]);
3801 
3802  Boundary_segment_final_arclength[b].push_back(
3803  initial_segment_arclength[is] + segment_arclength[is]);
3804 
3805  } // else if (boundary_geom_object_pt(b)!=0)
3806 
3807  } // // for (is < nsegments)
3808 
3809  // Get the number of segments from the sets of nodes
3810 #ifdef PARANOID
3811  if (segment_all_nodes_pt.size() != nsegments)
3812  {
3813  std::ostringstream error_message;
3814  error_message << "The number of segments (" << nsegments
3815  << ") and the number of "
3816  << "set of nodes (" << segment_all_nodes_pt.size()
3817  << ") representing\n"
3818  << "the\nsegments is different!!!\n\n";
3819  throw OomphLibError(error_message.str(),
3820  "TriangleMesh::compute_boundary_segments_"
3821  "connectivity_and_initial_zeta_values()",
3822  OOMPH_EXCEPTION_LOCATION);
3823  }
3824 #endif
3825 
3826  // The nodes have been assigned arc-length coordinates from one end
3827  // or the other of the connected segment.
3828 
3829  // -----------------------------------------------------------------
3830  // If mesh is distributed get the info. regarding the initial and
3831  // final nodes coordinates on the boundary, same as the zeta
3832  // boundary values for those nodes
3833 
3834  // Storage for the coordinates of the first and last nodes on the
3835  // boundary
3836  Vector<double> first_coordinate(2);
3837  Vector<double> last_coordinate(2);
3838 
3839  // Storage for the zeta coordinate of the first and last nodes on
3840  // the boundary
3841  Vector<double> first_node_zeta_coordinate(1, 0.0);
3842  Vector<double> last_node_zeta_coordinate(1, 0.0);
3843 
3844  // Send three data to all processors, the x[0], x[1] coordinate and
3845  // the zeta coordinate
3846  const unsigned ndtotal_data = 3;
3847  Vector<double> flat_packed_double_data_initial_seg(ndtotal_data);
3848 
3849  // If the mesh is distributed then check if this processor has the
3850  // initial segment
3851  if (my_rank == proc_with_initial_seg)
3852  {
3853  // Stores the firts element of the segment
3854  FiniteElement* first_ele_pt = 0;
3855  // Stores the first node of the boundary
3856  Node* first_node_pt = 0;
3857  // Check if the segment is inverted
3858  if (!segment_inverted[initial_segment])
3859  {
3860  // Get access to the first element on the segment marked as
3861  // initial
3862  first_ele_pt = segment_sorted_ele_pt[initial_segment].front();
3863 
3864  // Number of nodes
3865  const unsigned nnod = first_ele_pt->nnode();
3866 
3867  // Get the first node of the current segment
3868  first_node_pt = first_ele_pt->node_pt(0);
3869  if (is_inverted[first_ele_pt])
3870  {
3871  first_node_pt = first_ele_pt->node_pt(nnod - 1);
3872  }
3873  } // if (!segment_inverted[initial_segment])
3874  else
3875  {
3876  // Get access to the first element on the segment marked as
3877  // initial
3878  first_ele_pt = segment_sorted_ele_pt[initial_segment].back();
3879 
3880  // Number of nodes
3881  const unsigned nnod = first_ele_pt->nnode();
3882 
3883  // Get the first node of the current segment
3884  first_node_pt = first_ele_pt->node_pt(nnod - 1);
3885  if (is_inverted[first_ele_pt])
3886  {
3887  first_node_pt = first_ele_pt->node_pt(0);
3888  }
3889  } // else if (!segment_inverted[initial_segment])
3890 
3891  // Get the coordinates for the first node
3892  for (unsigned i = 0; i < 2; i++)
3893  {
3894  flat_packed_double_data_initial_seg[i] = first_node_pt->x(i);
3895  }
3896 
3897  // Get the zeta coordinates for the first node
3898  Vector<double> tmp_zeta(1);
3899  first_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3900 
3901  // If there is a geometric object associated to the boundary then
3902  // further process is necessary
3903  if (this->boundary_geom_object_pt(b) != 0)
3904  {
3905  // tmp_zeta[0] = this->boundary_coordinate_limits(b)[0];
3906  }
3907  else
3908  {
3909  // Check if the initial boundary coordinate is different from
3910  // zero, if that is the case then we need to set it to zero
3911  if (tmp_zeta[0] >= 1.0e-14)
3912  {
3913  tmp_zeta[0] = 0;
3914  }
3915  } // if (this->boundary_geom_object_pt(b)!=0)
3916 
3917  // Store the initial zeta value
3918  flat_packed_double_data_initial_seg[2] = tmp_zeta[0];
3919 
3920  } // if (my_rank == proc_with_initial_seg)
3921 
3922  // All processor receive the info. from the processor that has the
3923  // initial segment
3924  MPI_Bcast(&flat_packed_double_data_initial_seg[0],
3925  ndtotal_data,
3926  MPI_DOUBLE,
3927  proc_with_initial_seg,
3928  comm_pt->mpi_comm());
3929 
3930  // ... and all processor put that info. into the appropriate
3931  // storages
3932  for (unsigned i = 0; i < 2; i++)
3933  {
3934  first_coordinate[i] = flat_packed_double_data_initial_seg[i];
3935  }
3936  first_node_zeta_coordinate[0] = flat_packed_double_data_initial_seg[2];
3937 
3938  // -----------------------------------------------------------------
3939  // Send three data to all processors, the x[0], x[1] coordinate and
3940  // the zeta coordinate
3941  Vector<double> flat_packed_double_data_final_seg(ndtotal_data);
3942 
3943  // If the mesh is distributed then check if this processor has the
3944  // final segment
3945  if (my_rank == proc_with_final_seg)
3946  {
3947  // Get access to the last element on the segment
3948  FiniteElement* last_ele_pt = 0;
3949 
3950  // Get the last node of the current segment
3951  Node* last_node_pt = 0;
3952 
3953  // Check if the segment is inverted
3954  if (!segment_inverted[final_segment])
3955  {
3956  // Get access to the last element on the segment marked as
3957  // final
3958  last_ele_pt = segment_sorted_ele_pt[final_segment].back();
3959 
3960  // Number of nodes
3961  const unsigned nnod = last_ele_pt->nnode();
3962 
3963  // Get the last node of the current segment
3964  last_node_pt = last_ele_pt->node_pt(nnod - 1);
3965  if (is_inverted[last_ele_pt])
3966  {
3967  last_node_pt = last_ele_pt->node_pt(0);
3968  }
3969  } // if (!segment_inverted[final_segment])
3970  else
3971  {
3972  // Get access to the first element on the segment marked as
3973  // initial
3974  last_ele_pt = segment_sorted_ele_pt[final_segment].front();
3975 
3976  // Number of nodes
3977  const unsigned nnod = last_ele_pt->nnode();
3978 
3979  // Get the first node of the current segment
3980  last_node_pt = last_ele_pt->node_pt(0);
3981  if (is_inverted[last_ele_pt])
3982  {
3983  last_node_pt = last_ele_pt->node_pt(nnod - 1);
3984  }
3985  } // if (!segment_inverted[final_segment])
3986 
3987  // Get the coordinates for the last node
3988  for (unsigned i = 0; i < 2; i++)
3989  {
3990  flat_packed_double_data_final_seg[i] = last_node_pt->x(i);
3991  }
3992 
3993  // Get the zeta coordinates for the last node
3994  Vector<double> tmp_zeta(1);
3995  last_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3996 
3997  // If there is not a geometric object associated to the boundary
3998  // then further process is required
3999  if (this->boundary_geom_object_pt(b) != 0)
4000  {
4001  // Do nothing
4002  } // if (this->boundary_geom_object_pt(b)!=0)
4003  else
4004  {
4005  // Check if the final boundary coordinate is different from
4006  // the boundary arclength, if that is the case then we need
4007  // to set it to the accumulated arclength
4008  if (std::fabs(tmp_zeta[0] - root_accumulated_arclength) >= 1.0e-14)
4009  {
4010  tmp_zeta[0] = root_accumulated_arclength;
4011  }
4012  } // else if (this->boundary_geom_object_pt(b)!=0)
4013 
4014  // Store the final zeta value
4015  flat_packed_double_data_final_seg[2] = tmp_zeta[0];
4016 
4017  } // if (my_rank == proc_with_final_seg)
4018 
4019  // All processor receive the info. from the processor that has the
4020  // final segment
4021  MPI_Bcast(&flat_packed_double_data_final_seg[0],
4022  ndtotal_data,
4023  MPI_DOUBLE,
4024  proc_with_final_seg,
4025  comm_pt->mpi_comm());
4026 
4027  // All processor receive the info. from the processor that has the
4028  // final segment
4029  for (unsigned i = 0; i < 2; i++)
4030  {
4031  last_coordinate[i] = flat_packed_double_data_final_seg[i];
4032  }
4033  last_node_zeta_coordinate[0] = flat_packed_double_data_final_seg[2];
4034 
4035  // -----------------------------------------------------------------
4036  // Copy the values to the permanent storage
4037  Boundary_initial_coordinate[b] = first_coordinate;
4038  Boundary_final_coordinate[b] = last_coordinate;
4039 
4040  Boundary_initial_zeta_coordinate[b] = first_node_zeta_coordinate;
4041  Boundary_final_zeta_coordinate[b] = last_node_zeta_coordinate;
4042 
4043  // If we are dealing with an internal boundary then re-assign the
4044  // initial and final zeta values for the segments
4045  if (is_internal_boundary)
4046  {
4047  // Only re-assign zeta values if there are at least one nonhalo
4048  // segment, if all the possible segments are halo then the
4049  // synchronisation method will be in charge of assigning the
4050  // correct boundary coordinates
4051  if (nsegments > 0)
4052  {
4053  // Call the following method to re-construct the segments but
4054  // using only the nonhalo elements, therefore the boundary
4055  // coordinates need to be re-assigned
4056  re_assign_initial_zeta_values_for_internal_boundary(
4057  b, segment_sorted_nonhalo_ele_pt, is_inverted);
4058  }
4059 
4060  } // if (is_internal_boundary)
4061 
4062  // Now identify the boundary segments
4063  if (nsegments > 0)
4064  {
4065  // Identify the boundary segments in the current mesh
4066  // identify_boundary_segments_and_assign_initial_zeta_values(
4067  // b, all_face_ele_pt, is_internal_boundary, face_to_bulk_element_pt);
4068  identify_boundary_segments_and_assign_initial_zeta_values(b, this);
4069  } // if (nsegments > 0)
4070 
4071  // Clean all the created face elements
4072  for (unsigned i = 0; i < n_all_face_ele; i++)
4073  {
4074  delete all_face_ele_pt[i];
4075  all_face_ele_pt[i] = 0;
4076  }
4077  }
4078 
4079  //======================================================================
4080  /// \short Re-assign the boundary segments initial zeta (arclength)
4081  /// for those internal boundaries that were splited during the
4082  /// distribution process. Those boundaries that have one face element
4083  /// at each side of the boundary. Here we create the segments only
4084  /// with the nonhalo elements, therefore the boundary coordinates
4085  /// need to be re-assigned to be passed to the new meshes
4086  //======================================================================
4087  template<class ELEMENT>
4090  const unsigned& b,
4091  Vector<std::list<FiniteElement*>>& old_segment_sorted_ele_pt,
4092  std::map<FiniteElement*, bool>& old_is_inverted)
4093  {
4094  // ------------------------------------------------------------------
4095  // First: Get the face elements associated with the current boundary
4096  // Only include nonhalo face elements
4097  // ------------------------------------------------------------------
4098  // Temporary storage for face elements
4099  Vector<FiniteElement*> face_el_pt;
4100 
4101  // Temporary storage for the number of elements adjacent to the
4102  // boundary
4103  unsigned nele = 0;
4104 
4105  // Temporary storage for elements adjacent to the boundary that have
4106  // a common edge (related with internal boundaries)
4107  unsigned n_repeated_ele = 0;
4108 
4109  const unsigned n_regions = this->nregion();
4110 
4111  // Temporary storage for already done nodes
4112  Vector<std::pair<Node*, Node*>> done_nodes_pt;
4113 
4114  // If there is more than one region then only use boundary
4115  // coordinates from the bulk side (region 0)
4116  if (n_regions > 1)
4117  {
4118  for (unsigned rr = 0; rr < n_regions; rr++)
4119  {
4120  const unsigned region_id =
4121  static_cast<unsigned>(this->Region_attribute[rr]);
4122 
4123  // Loop over all elements on boundaries in region i_r
4124  const unsigned nel_in_region =
4125  this->nboundary_element_in_region(b, region_id);
4126 
4127  unsigned nel_repetead_in_region = 0;
4128 
4129  // Only bother to do anything else, if there are elements
4130  // associated with the boundary and the current region
4131  if (nel_in_region > 0)
4132  {
4133  bool repeated = false;
4134 
4135  // Loop over the bulk elements adjacent to boundary b
4136  for (unsigned e = 0; e < nel_in_region; e++)
4137  {
4138  // Get pointer to the bulk element that is adjacent to
4139  // boundary b
4140  FiniteElement* bulk_elem_pt =
4141  this->boundary_element_in_region_pt(b, region_id, e);
4142 
4143  // Remember only work with non halo elements
4144  if (bulk_elem_pt->is_halo())
4145  {
4146  n_repeated_ele++;
4147  continue;
4148  }
4149 
4150  // Find the index of the face of element e along boundary b
4151  int face_index =
4152  this->face_index_at_boundary_in_region(b, region_id, e);
4153 
4154  // Before adding the new element we need to be sure that the
4155  // edge that this element represent has not been already
4156  // added
4157  FiniteElement* tmp_ele_pt =
4158  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4159 
4160  const unsigned n_nodes = tmp_ele_pt->nnode();
4161 
4162  std::pair<Node*, Node*> tmp_pair = std::make_pair(
4163  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
4164 
4165  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
4166  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
4167 
4168  // Search for repeated nodes
4169  const unsigned repeated_nodes_size = done_nodes_pt.size();
4170  for (unsigned l = 0; l < repeated_nodes_size; l++)
4171  {
4172  if (tmp_pair == done_nodes_pt[l] ||
4173  tmp_pair_inverse == done_nodes_pt[l])
4174  {
4175  nel_repetead_in_region++;
4176  repeated = true;
4177  break;
4178  }
4179  }
4180 
4181  // Create new face element
4182  if (!repeated)
4183  {
4184  // Add the pair of nodes (edge) to the node dones
4185  done_nodes_pt.push_back(tmp_pair);
4186  // Add the element to the face elements
4187  face_el_pt.push_back(tmp_ele_pt);
4188  }
4189  else
4190  {
4191  // Clean up
4192  delete tmp_ele_pt;
4193  tmp_ele_pt = 0;
4194  }
4195 
4196  // Re-start
4197  repeated = false;
4198 
4199  } // for nel
4200 
4201  nele += nel_in_region;
4202 
4203  n_repeated_ele += nel_repetead_in_region;
4204 
4205  } // if (nel_in_region > 0)
4206  } // for (rr < n_regions)
4207  } // if (n_regions > 1)
4208  // Otherwise it's just the normal boundary functions
4209  else
4210  {
4211  // Loop over all elements on boundaries
4212  nele = this->nboundary_element(b);
4213 
4214  // Only bother to do anything else, if there are elements
4215  if (nele > 0)
4216  {
4217  // Check for repeated ones
4218  bool repeated = false;
4219 
4220  // Loop over the bulk elements adjacent to boundary b
4221  for (unsigned e = 0; e < nele; e++)
4222  {
4223  // Get pointer to the bulk element that is adjacent to
4224  // boundary b
4225  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
4226 
4227  // Skip the halo elements, they are not included
4228  if (bulk_elem_pt->is_halo())
4229  {
4230  n_repeated_ele++;
4231  continue;
4232  }
4233 
4234  // Find the index of the face of element e along boundary b
4235  int face_index = this->face_index_at_boundary(b, e);
4236 
4237  // Before adding the new element we need to be sure that the
4238  // edge that this element represents has not been already
4239  // added (only applies for internal boundaries)
4240  FiniteElement* tmp_ele_pt =
4241  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4242 
4243  const unsigned n_nodes = tmp_ele_pt->nnode();
4244 
4245  std::pair<Node*, Node*> tmp_pair = std::make_pair(
4246  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
4247 
4248  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
4249  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
4250 
4251  // Search for repeated nodes
4252  const unsigned repeated_nodes_size = done_nodes_pt.size();
4253  for (unsigned l = 0; l < repeated_nodes_size; l++)
4254  {
4255  if (tmp_pair == done_nodes_pt[l] ||
4256  tmp_pair_inverse == done_nodes_pt[l])
4257  {
4258  // Increase the number of repeated elements
4259  n_repeated_ele++;
4260  // Mark the element as repeated
4261  repeated = true;
4262  break;
4263  }
4264  }
4265 
4266  // Create new face element
4267  if (!repeated)
4268  {
4269  // Add the pair of nodes (edge) to the node dones
4270  done_nodes_pt.push_back(tmp_pair);
4271  // Add the element to the face elements
4272  face_el_pt.push_back(tmp_ele_pt);
4273  }
4274  else
4275  {
4276  // Free the repeated bulk element!!
4277  delete tmp_ele_pt;
4278  tmp_ele_pt = 0;
4279  }
4280 
4281  // Re-start
4282  repeated = false;
4283 
4284  } // for (e < nel)
4285  } // if (nel > 0)
4286 
4287  } // else (n_regions > 1)
4288 
4289  // Do not consider the repeated elements
4290  nele -= n_repeated_ele;
4291 
4292 #ifdef PARANOID
4293  if (nele != face_el_pt.size())
4294  {
4295  std::ostringstream error_message;
4296  error_message
4297  << "The independet counting of face elements (" << nele << ") for "
4298  << "boundary (" << b << ") is different\n"
4299  << "from the real number of face elements in the container ("
4300  << face_el_pt.size() << ")\n";
4301  //<< "Possible memory leak\n"
4302  throw OomphLibError(
4303  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4304  }
4305 #endif
4306 
4307  // ----------------------------------------------------------------
4308  // Second: Sort the face elements, only consider nonhalo elements
4309  // ----------------------------------------------------------------
4310 
4311  // Get the total number of nonhalo face elements
4312  const unsigned nnon_halo_face_elements = face_el_pt.size();
4313 
4314  // The vector of list to store the "segments" that compound the
4315  // boundary (segments may appear only in a distributed mesh)
4316  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
4317 
4318  // Number of already sorted face elements
4319  unsigned nsorted_face_elements = 0;
4320 
4321  // Keep track of who's done
4322  std::map<FiniteElement*, bool> done_el;
4323 
4324  // Keep track of which element is inverted
4325  std::map<FiniteElement*, bool> is_inverted;
4326 
4327  // Iterate until all possible segments have been created
4328  while (nsorted_face_elements < nnon_halo_face_elements)
4329  {
4330  // The ordered list of face elements (in a distributed mesh a
4331  // collection of contiguous face elements define a segment)
4332  std::list<FiniteElement*> sorted_el_pt;
4333 
4334 #ifdef PARANOID
4335  // Select an initial element for the segment
4336  bool found_initial_face_element = false;
4337 #endif
4338 
4339  FiniteElement* ele_face_pt = 0;
4340 
4341  unsigned iface = 0;
4342  for (iface = 0; iface < nele; iface++)
4343  {
4344  ele_face_pt = face_el_pt[iface];
4345  // If not done then take it as initial face element
4346  if (!done_el[ele_face_pt])
4347  {
4348 #ifdef PARANOID
4349  // Mark as found the root face element
4350  found_initial_face_element = true;
4351 #endif
4352  // Increase the number of sorted face elements
4353  nsorted_face_elements++;
4354  // Increase the counter to mark the position of the next
4355  // element number
4356  iface++;
4357  // Add the face element in the list of sorted face elements
4358  sorted_el_pt.push_back(ele_face_pt);
4359  // Mark as done
4360  done_el[ele_face_pt] = true;
4361  break;
4362  } // if (!done_el[ele_face_pt])
4363  } // for (iface < nele)
4364 
4365 #ifdef PARANOID
4366  if (!found_initial_face_element)
4367  {
4368  std::ostringstream error_message;
4369  error_message
4370  << "Could not find an initial face element for the current segment\n";
4371  throw OomphLibError(
4372  error_message.str(),
4373  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4374  OOMPH_EXCEPTION_LOCATION);
4375  }
4376 #endif
4377 
4378  // Number of nodes
4379  const unsigned nnod = ele_face_pt->nnode();
4380 
4381  // Left and rightmost nodes (the left and right nodes of the
4382  // current face element)
4383  Node* left_node_pt = ele_face_pt->node_pt(0);
4384  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
4385 
4386  // Continue iterating if a new face element has been added to the
4387  // list
4388  bool face_element_added = false;
4389 
4390  // While a new face element has been added to the set of sorted
4391  // face elements then re-iterate
4392  do
4393  {
4394  // Start from the next face element since we have already added
4395  // the previous one as the initial face element (any previous
4396  // face element had to be added on previous iterations)
4397  for (unsigned iiface = iface; iiface < nele; iiface++)
4398  {
4399  // Re-start flag
4400  face_element_added = false;
4401 
4402  // Get the candidate element
4403  ele_face_pt = face_el_pt[iiface];
4404 
4405  // Check that the candidate element has not been done and is
4406  // not a halo element
4407  if (!(done_el[ele_face_pt]))
4408  {
4409  // Get the left and right nodes of the current element
4410  Node* local_left_node_pt = ele_face_pt->node_pt(0);
4411  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
4412 
4413  // New element fits at the left of segment and is not inverted
4414  if (left_node_pt == local_right_node_pt)
4415  {
4416  left_node_pt = local_left_node_pt;
4417  sorted_el_pt.push_front(ele_face_pt);
4418  is_inverted[ele_face_pt] = false;
4419  face_element_added = true;
4420  }
4421  // New element fits at the left of segment and is inverted
4422  else if (left_node_pt == local_left_node_pt)
4423  {
4424  left_node_pt = local_right_node_pt;
4425  sorted_el_pt.push_front(ele_face_pt);
4426  is_inverted[ele_face_pt] = true;
4427  face_element_added = true;
4428  }
4429  // New element fits on the right of segment and is not inverted
4430  else if (right_node_pt == local_left_node_pt)
4431  {
4432  right_node_pt = local_right_node_pt;
4433  sorted_el_pt.push_back(ele_face_pt);
4434  is_inverted[ele_face_pt] = false;
4435  face_element_added = true;
4436  }
4437  // New element fits on the right of segment and is inverted
4438  else if (right_node_pt == local_right_node_pt)
4439  {
4440  right_node_pt = local_left_node_pt;
4441  sorted_el_pt.push_back(ele_face_pt);
4442  is_inverted[ele_face_pt] = true;
4443  face_element_added = true;
4444  }
4445 
4446  if (face_element_added)
4447  {
4448  done_el[ele_face_pt] = true;
4449  nsorted_face_elements++;
4450  break;
4451  } // if (face_element_added)
4452 
4453  } // if (!(done_el[ele_face_pt]))
4454 
4455  } // for (iiface<nnon_halo_face_element)
4456 
4457  } while (face_element_added &&
4458  (nsorted_face_elements < nnon_halo_face_elements));
4459 
4460  // Store the created segment in the vector of segments
4461  segment_sorted_ele_pt.push_back(sorted_el_pt);
4462 
4463  } // while(nsorted_face_elements < nnon_halo_face_elements);
4464 
4465  // --------------------------------------------------------------
4466  // Third: We have the face elements sorted, now assign boundary
4467  // coordinates to the nodes in the segments and compute the
4468  // arclength of the segment.
4469  // --------------------------------------------------------------
4470 
4471  // The number of segments in this processor
4472  const unsigned nsegments = segment_sorted_ele_pt.size();
4473 
4474 #ifdef PARANOID
4475  if (nnon_halo_face_elements > 0 && nsegments == 0)
4476  {
4477  std::ostringstream error_message;
4478  error_message
4479  << "The number of segments is zero, but the number of nonhalo\n"
4480  << "elements is: (" << nnon_halo_face_elements << ")\n";
4481  throw OomphLibError(
4482  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4483  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
4484 #endif
4485 
4486  // Vector of sets that stores the nodes of each segment based on a
4487  // lexicographically order starting from the bottom left node of
4488  // each segment
4489  Vector<std::set<Node*>> segment_all_nodes_pt(nsegments);
4490 
4491  // Stores the nodes on each segment in the order they appear in the
4492  // face elements
4493  Vector<Vector<Node*>> sorted_segment_all_nodes_pt(nsegments);
4494 
4495  // Associate and arclength to each node on each segment of the
4496  // boundary, the nodes and therefore the arclength come in the same
4497  // order as the face elements
4498  Vector<Vector<double>> sorted_segment_node_arclength(nsegments);
4499 
4500  // The arclength of each segment in the current processor
4501  Vector<double> segment_arclength(nsegments);
4502 
4503  // The number of vertices of each segment
4504  Vector<unsigned> nvertices_per_segment(nsegments);
4505 
4506  // The initial zeta for the segment
4507  Vector<double> initial_zeta_segment(nsegments);
4508 
4509  // The final zeta for the segment
4510  Vector<double> final_zeta_segment(nsegments);
4511 
4512  // Go through all the segments and compute the LOCAL boundary
4513  // coordinates
4514  for (unsigned is = 0; is < nsegments; is++)
4515  {
4516 #ifdef PARANOID
4517  if (segment_sorted_ele_pt[is].size() == 0)
4518  {
4519  std::ostringstream error_message;
4520  error_message << "The (" << is << ")-th segment has no elements\n";
4521  throw OomphLibError(
4522  error_message.str(),
4523  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4524  OOMPH_EXCEPTION_LOCATION);
4525  } // if (segment_sorted_ele_pt[is].size() == 0)
4526 #endif
4527 
4528  // Get access to the first element on the segment
4529  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
4530 
4531  // Number of nodes
4532  const unsigned nnod = first_ele_pt->nnode();
4533 
4534  // Get the first node of the current segment
4535  Node* first_node_pt = first_ele_pt->node_pt(0);
4536  if (is_inverted[first_ele_pt])
4537  {
4538  first_node_pt = first_ele_pt->node_pt(nnod - 1);
4539  }
4540 
4541  // Coordinates of left node
4542  double x_left = first_node_pt->x(0);
4543  double y_left = first_node_pt->x(1);
4544 
4545  // Initialise boundary coordinate (local boundary coordinate for
4546  // boundaries with more than one segment)
4547  Vector<double> zeta(1, 0.0);
4548 
4549  // If we have associated a GeomObject then it is not necessary
4550  // to compute the arclength, only read the values from the nodes at
4551  // the edges
4552  if (this->boundary_geom_object_pt(b) != 0)
4553  {
4554  first_node_pt->get_coordinates_on_boundary(b, zeta);
4555  initial_zeta_segment[is] = zeta[0];
4556 
4557  // Get access to the last element on the segment
4558  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
4559 
4560  // Get the last node of the current segment
4561  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
4562  if (is_inverted[last_ele_pt])
4563  {
4564  last_node_pt = last_ele_pt->node_pt(0);
4565  }
4566 
4567  last_node_pt->get_coordinates_on_boundary(b, zeta);
4568  final_zeta_segment[is] = zeta[0];
4569  }
4570 
4571  // Sort the nodes in the segment (lexicographically bottom left
4572  // node)
4573  std::set<Node*> local_nodes_pt;
4574  local_nodes_pt.insert(first_node_pt);
4575 
4576  // Associate and arclength to the sorted nodes
4577  Vector<double> sorted_node_arclength;
4578  sorted_node_arclength.push_back(0.0);
4579 
4580  // Sorts the nodes in the segments according their sorting in the
4581  // face elements
4582  Vector<Node*> sorted_nodes_pt;
4583  sorted_nodes_pt.push_back(first_node_pt);
4584 
4585  // Now loop over nodes in order
4586  for (std::list<FiniteElement*>::iterator it =
4587  segment_sorted_ele_pt[is].begin();
4588  it != segment_sorted_ele_pt[is].end();
4589  it++)
4590  {
4591  // Get the face element
4592  FiniteElement* el_pt = *it;
4593 
4594  // Start node and increment
4595  unsigned k_nod = 1;
4596  int nod_diff = 1;
4597  if (is_inverted[el_pt])
4598  {
4599  k_nod = nnod - 2;
4600  nod_diff = -1;
4601  }
4602 
4603  // Loop over nodes
4604  for (unsigned j = 1; j < nnod; j++)
4605  {
4606  Node* nod_pt = el_pt->node_pt(k_nod);
4607  k_nod += nod_diff;
4608 
4609  // Coordinates of right node
4610  double x_right = nod_pt->x(0);
4611  double y_right = nod_pt->x(1);
4612 
4613  // Increment boundary coordinate
4614  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
4615  (y_right - y_left) * (y_right - y_left));
4616 
4617  // When we have a GeomObject associated to the boundary we already
4618  // know the zeta values for the nodes, there is no need to compute
4619  // the arclength
4620  if (this->boundary_geom_object_pt(b) == 0)
4621  {
4622  // Set boundary coordinate
4623  // nod_pt->set_coordinates_on_boundary(b, zeta);
4624  }
4625 
4626  // Increment reference coordinate
4627  x_left = x_right;
4628  y_left = y_right;
4629 
4630  // Get lexicographically bottom left node but only
4631  // use vertex nodes as candidates
4632  local_nodes_pt.insert(nod_pt);
4633 
4634  // Associate the arclength for the current node
4635  sorted_node_arclength.push_back(zeta[0]);
4636 
4637  // Store the node in the sorted nodes storage
4638  sorted_nodes_pt.push_back(nod_pt);
4639 
4640  } // for (j < nnod)
4641 
4642  } // iterator over the elements in the segment
4643 
4644  // Info. to be passed to the other processors
4645  // The initial arclength for the segment that goes after this depends
4646  // on the current segment arclength
4647  segment_arclength[is] = zeta[0];
4648 
4649  // Info. to be passed to the other processors
4650  // The initial vertex number for the segment that goes after this
4651  // depends on the current sement vertices number
4652  nvertices_per_segment[is] = local_nodes_pt.size();
4653 
4654  // Add the nodes for the corresponding segment in the container
4655  segment_all_nodes_pt[is] = local_nodes_pt;
4656 
4657  // Add the arclengths to the nodes in the segment
4658  sorted_segment_node_arclength[is] = sorted_node_arclength;
4659 
4660  // Add the sorted nodes to the storage
4661  sorted_segment_all_nodes_pt[is] = sorted_nodes_pt;
4662 
4663  // The attaching of the halo elements at both sides of the segments is
4664  // performed only if segments connectivity needs to be computed
4665 
4666  } // for (is < nsegments)
4667 
4668  // ------------------------------------------------------------------
4669  // Fourth: Now we have the segments sorted, with arclength and with
4670  // LOCAL boundary coordinates assigned to the nodes. Identify the
4671  // nodes on the segments with the input segments and re-assign all
4672  // the info. related with the identification of segments
4673  // ------------------------------------------------------------------
4674 
4675  // Get the number of segments for the old sorted segments
4676  const unsigned old_nsegments = old_segment_sorted_ele_pt.size();
4677 
4678  // ------------------------------------------------------------------
4679  // Copy the old info. in temporary storages
4680  Vector<unsigned> old_boundary_segment_inverted(old_nsegments);
4681 
4682  Vector<Vector<double>> old_boundary_segment_initial_coordinate(
4683  old_nsegments);
4684  Vector<Vector<double>> old_boundary_segment_final_coordinate(old_nsegments);
4685 
4686  Vector<double> old_boundary_segment_initial_zeta(old_nsegments);
4687  Vector<double> old_boundary_segment_final_zeta(old_nsegments);
4688 
4689  Vector<double> old_boundary_segment_initial_arclength(old_nsegments);
4690  Vector<double> old_boundary_segment_final_arclength(old_nsegments);
4691 
4692  // Back-up the information
4693  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4694  {
4695  old_boundary_segment_inverted[old_is] =
4696  boundary_segment_inverted(b)[old_is];
4697 
4698  old_boundary_segment_initial_coordinate[old_is].resize(2);
4699  old_boundary_segment_final_coordinate[old_is].resize(2);
4700  for (unsigned i = 0; i < 2; i++)
4701  {
4702  old_boundary_segment_initial_coordinate[old_is][i] =
4703  boundary_segment_initial_coordinate(b)[old_is][i];
4704 
4705  old_boundary_segment_final_coordinate[old_is][i] =
4706  boundary_segment_final_coordinate(b)[old_is][i];
4707  }
4708 
4709  // Check if the boundary has an associated GeomObject
4710  if (this->boundary_geom_object_pt(b) != 0)
4711  {
4712  old_boundary_segment_initial_zeta[old_is] =
4713  boundary_segment_initial_zeta(b)[old_is];
4714 
4715  old_boundary_segment_final_zeta[old_is] =
4716  boundary_segment_final_zeta(b)[old_is];
4717 
4718  } // if (this->boundary_geom_object_pt(b)!=0)
4719  else
4720  {
4721  old_boundary_segment_initial_arclength[old_is] =
4722  boundary_segment_initial_arclength(b)[old_is];
4723 
4724  old_boundary_segment_final_arclength[old_is] =
4725  boundary_segment_final_arclength(b)[old_is];
4726 
4727  } // else if (this->boundary_geom_object_pt(b)!=0)
4728 
4729  } // for (old_is < old_nsegments)
4730 
4731  // ------------------------------------------------------------------
4732  // Now clear the original storages
4733  Boundary_segment_inverted[b].clear();
4734  Boundary_segment_initial_coordinate[b].clear();
4735  Boundary_segment_final_coordinate[b].clear();
4736 
4737  Boundary_segment_initial_zeta[b].clear();
4738  Boundary_segment_final_zeta[b].clear();
4739 
4740  Boundary_segment_initial_arclength[b].clear();
4741  Boundary_segment_final_arclength[b].clear();
4742  // ------------------------------------------------------------------
4743  // .. and resize the storages for the new number of segments
4744  Boundary_segment_inverted[b].resize(nsegments);
4745  Boundary_segment_initial_coordinate[b].resize(nsegments);
4746  Boundary_segment_final_coordinate[b].resize(nsegments);
4747 
4748  // Check if the boundary has an associated GeomObject
4749  if (this->boundary_geom_object_pt(b) != 0)
4750  {
4751  Boundary_segment_initial_zeta[b].resize(nsegments);
4752  Boundary_segment_final_zeta[b].resize(nsegments);
4753  }
4754  else
4755  {
4756  Boundary_segment_initial_arclength[b].resize(nsegments);
4757  Boundary_segment_final_arclength[b].resize(nsegments);
4758  }
4759  // ------------------------------------------------------------------
4760  // map to know if the new segment has been re-assigned the info.
4761  std::map<unsigned, bool> done_segment;
4762 
4763  // Count the number of re-assigned segments with the new values
4764  unsigned re_assigned_segments = 0;
4765 
4766  // Go through all the old segments (the input segments)
4767  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4768  {
4769  // Get the first and last zeta values for the current segment
4770  const double old_initial_arclength =
4771  old_boundary_segment_initial_arclength[old_is];
4772  const double old_final_arclength =
4773  old_boundary_segment_final_arclength[old_is];
4774  // Get the "is inverted" segment information
4775  const unsigned old_inverted_segment =
4776  old_boundary_segment_inverted[old_is];
4777 
4778  // Check if the boundary coordinates in the segment go in
4779  // increasing or decreasing order
4780  bool old_increasing_order = false;
4781  if (old_initial_arclength < old_final_arclength)
4782  {
4783  old_increasing_order = true;
4784  }
4785 
4786  // Now get the first and last node of the current segment
4787  // Get the first element
4788  FiniteElement* first_old_seg_ele_pt =
4789  old_segment_sorted_ele_pt[old_is].front();
4790 
4791  // Number of nodes
4792  const unsigned nnod = first_old_seg_ele_pt->nnode();
4793 
4794  // Get the first node of the current segment
4795  Node* first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(0);
4796  if (old_is_inverted[first_old_seg_ele_pt])
4797  {
4798  first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(nnod - 1);
4799  }
4800 
4801  // Get access to the last element on the segment
4802  FiniteElement* last_old_seg_ele_pt =
4803  old_segment_sorted_ele_pt[old_is].back();
4804 
4805  // Get the last node of the current segment
4806  Node* last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(nnod - 1);
4807  if (old_is_inverted[last_old_seg_ele_pt])
4808  {
4809  last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(0);
4810  }
4811  // Check if the segment is inverted, if that is the case then
4812  // also invert the nodes
4813  if (old_inverted_segment)
4814  {
4815  Node* temp_node_pt = first_old_seg_node_pt;
4816  first_old_seg_node_pt = last_old_seg_node_pt;
4817  last_old_seg_node_pt = temp_node_pt;
4818  }
4819 
4820  // We have the first and last node of the old segment (input
4821  // segment), now identify in which segment, of those with only
4822  // nonhalo face elements, they are
4823  for (unsigned is = 0; is < nsegments; is++)
4824  {
4825  if (!done_segment[is])
4826  {
4827  // Go through the nodes of the current segment and try to find
4828  // the old nodes
4829  bool found_first_old_seg_node = false;
4830  bool found_last_old_seg_node = false;
4831  bool same_order = false;
4832 
4833  // Get the first node of the current segment
4834  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
4835  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
4836  if (is_inverted[first_seg_ele_pt])
4837  {
4838  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod - 1);
4839  }
4840 
4841  // Get the arclength for the first node
4842  const double segment_first_node_zeta =
4843  sorted_segment_node_arclength[is][0];
4844 
4845  // Get the node coordinates for the first node
4846  Vector<double> first_node_coord(2);
4847  for (unsigned i = 0; i < 2; i++)
4848  {
4849  first_node_coord[i] = first_seg_node_pt->x(i);
4850  }
4851 
4852  // Get the last node of the current segment
4853  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
4854  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod - 1);
4855  if (is_inverted[last_seg_ele_pt])
4856  {
4857  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
4858  }
4859 
4860  // Get the arclength for the last node
4861  const double segment_final_node_zeta = segment_arclength[is];
4862 
4863  // Get the node coordinates for the last node
4864  Vector<double> last_node_coord(2);
4865  for (unsigned i = 0; i < 2; i++)
4866  {
4867  last_node_coord[i] = last_seg_node_pt->x(i);
4868  }
4869 
4870  // Temporary storage for the nodes of the current segment
4871  Vector<Node*> segment_node_pt = sorted_segment_all_nodes_pt[is];
4872  // Get the number of nodes in the segment
4873  const unsigned nsegment_node = segment_node_pt.size();
4874  for (unsigned in = 0; in < nsegment_node; in++)
4875  {
4876  Node* current_node_pt = segment_node_pt[in];
4877  if (!found_first_old_seg_node &&
4878  first_old_seg_node_pt == current_node_pt)
4879  {
4880  // Get the arclength assigned to the node on the old
4881  // segment
4882  const double current_node_zeta =
4883  sorted_segment_node_arclength[is][in];
4884 
4885  // Now check if the new segment has the same orientation
4886  // as the old one
4887  if (!found_last_old_seg_node) // has the same orientation
4888  {
4889  // Re-assign the first node coordinates
4890  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
4891 
4892  // Check if the boundary has an associated GeomObject
4893  if (this->boundary_geom_object_pt(b) != 0)
4894  {
4895  // Assign the zeta values if the current segment has the
4896  // nodes of the old one
4897 
4898  // If we are in the same order then pass the values as
4899  // they are
4900  Boundary_segment_initial_zeta[b][is] =
4901  initial_zeta_segment[is];
4902 
4903  } // if (this->boundary_geom_object_pt(b)!=0)
4904  else
4905  {
4906  // Get the distance to the first node
4907  const double distance =
4908  std::fabs(current_node_zeta - segment_first_node_zeta);
4909 
4910  double new_initial_arclength = old_initial_arclength;
4911 
4912  // Now check if the zeta values are in increasing order
4913  if (old_increasing_order)
4914  {
4915  // Substract the distance
4916  new_initial_arclength -= distance;
4917  }
4918  else
4919  {
4920  // Add the distance
4921  new_initial_arclength += distance;
4922  }
4923 
4924  // Re-assign the initial arclength for the current segment
4925  Boundary_segment_initial_arclength[b][is] =
4926  new_initial_arclength;
4927 
4928  } // else if (this->boundary_geom_object_pt(b)!=0)
4929  } // if (!found_last_old_seg_node)
4930  else // has different orientation
4931  {
4932  // Re-assign the first node coordinates
4933  Boundary_segment_initial_coordinate[b][is] = last_node_coord;
4934 
4935  // Check if the boundary has an associated GeomObject
4936  if (this->boundary_geom_object_pt(b) != 0)
4937  {
4938  // Assign the zeta values if the current segment has the
4939  // nodes of the old one
4940 
4941  // Not the same order, we need to copy the zeta values
4942  // from the other end, the inverted flag is changed at
4943  // the end. Copy the value from the final end
4944  Boundary_segment_initial_zeta[b][is] = final_zeta_segment[is];
4945 
4946  } // if (this->boundary_geom_object_pt(b)!=0)
4947  else
4948  {
4949  // Get the distance to the final node
4950  const double distance =
4951  std::fabs(current_node_zeta - segment_final_node_zeta);
4952 
4953  double new_initial_arclength = old_initial_arclength;
4954 
4955  // Now check if the zeta values are in increasing order
4956  if (old_increasing_order)
4957  {
4958  // Substract the distance
4959  new_initial_arclength -= distance;
4960  }
4961  else
4962  {
4963  // Add the distance
4964  new_initial_arclength += distance;
4965  }
4966 
4967  // Re-assign the initial arclength for the current segment
4968  Boundary_segment_initial_arclength[b][is] =
4969  new_initial_arclength;
4970 
4971  } // else if (this->boundary_geom_object_pt(b)!=0)
4972  } // else if (!found_last_old_seg_node)
4973 
4974  // Mark as found the first node
4975  found_first_old_seg_node = true;
4976  }
4977  // if (!found_first_old_seg_node &&
4978  // first_old_seg_node_pt == current_node_pt)
4979 
4980  // If we found first the first node then the segments have
4981  // the same order
4982  if (found_first_old_seg_node && !found_last_old_seg_node)
4983  {
4984  same_order = true;
4985  }
4986 
4987  if (!found_last_old_seg_node &&
4988  last_old_seg_node_pt == current_node_pt)
4989  {
4990  // Get the boundary coordinates assigned to the node on
4991  // the old segment
4992  const double current_node_zeta =
4993  sorted_segment_node_arclength[is][in];
4994 
4995  // Now check if the new segment has the same orientation
4996  // as the old one
4997  if (found_first_old_seg_node) // has the same orientation
4998  {
4999  // Re-assign the last node coordinates
5000  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5001 
5002  // Check if the boundary has an associated GeomObject
5003  if (this->boundary_geom_object_pt(b) != 0)
5004  {
5005  // Assign the zeta values if the current segment has the
5006  // nodes of the old one
5007 
5008  // If we are in the same order then pass the values as
5009  // they are
5010  Boundary_segment_final_zeta[b][is] = final_zeta_segment[is];
5011 
5012  } // if (this->boundary_geom_object_pt(b)!=0)
5013  else
5014  {
5015  // Get the distance to the last node
5016  const double distance =
5017  std::fabs(current_node_zeta - segment_final_node_zeta);
5018 
5019  double new_final_arclength = old_final_arclength;
5020 
5021  // Now check if the zeta values are in increasing order
5022  if (old_increasing_order)
5023  {
5024  // Add the distance
5025  new_final_arclength += distance;
5026  }
5027  else
5028  {
5029  // Substract the distance
5030  new_final_arclength -= distance;
5031  }
5032 
5033  // Re-assign the final arclength for the current segment
5034  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5035 
5036  } // else if (this->boundary_geom_object_pt(b)!=0)
5037  } // if (found_first_old_seg_node)
5038  else
5039  {
5040  // Re-assign the last node coordinates
5041  Boundary_segment_final_coordinate[b][is] = first_node_coord;
5042 
5043  // Check if the boundary has an associated GeomObject
5044  if (this->boundary_geom_object_pt(b) != 0)
5045  {
5046  // Assign the zeta values if the current segment has the
5047  // nodes of the old one
5048 
5049  // Not the same order, we need to copy the zeta values
5050  // from the other end, the inverted flag is changed at
5051  // the end. Copy the value from the initial end
5052  Boundary_segment_final_zeta[b][is] = initial_zeta_segment[is];
5053 
5054  } // if (this->boundary_geom_object_pt(b)!=0)
5055  else
5056  {
5057  // Get the distance to the last node
5058  const double distance =
5059  std::fabs(current_node_zeta - segment_first_node_zeta);
5060 
5061  double new_final_arclength = old_final_arclength;
5062 
5063  // Now check if the zeta values are in increasing order
5064  if (old_increasing_order)
5065  {
5066  // Add the distance
5067  new_final_arclength += distance;
5068  }
5069  else
5070  {
5071  // Substract the distance
5072  new_final_arclength -= distance;
5073  }
5074 
5075  // Re-assign the final arclength for the current segment
5076  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5077 
5078  } // else if (this->boundary_geom_object_pt(b)!=0)
5079  } // if (found_first_old_seg_node)
5080 
5081  // Mark as found the last node
5082  found_last_old_seg_node = true;
5083 
5084  } // if (!found_last_old_seg_node &&
5085  // last_old_seg_node_pt == current_node_pt)
5086 
5087  // If we found the last node first then the segments have
5088  // not the same order
5089  if (!found_first_old_seg_node && found_last_old_seg_node)
5090  {
5091  same_order = false;
5092  }
5093 
5094  if (found_first_old_seg_node && found_last_old_seg_node)
5095  {
5096  // Check if necessary to change the information that
5097  // states if a segment is inverted or not
5098  if (same_order)
5099  {
5100  Boundary_segment_inverted[b][is] = old_inverted_segment;
5101  }
5102  else
5103  {
5104  Boundary_segment_inverted[b][is] = !old_inverted_segment;
5105  }
5106 
5107  // Mark the segment as done
5108  done_segment[is] = true;
5109 
5110  // Increase the number of re-assigned segments
5111  re_assigned_segments++;
5112 
5113  // Break the for that look for the nodes in the segments
5114  break;
5115  }
5116 
5117  } // for (in < nsegment_node)
5118 
5119 #ifdef PARANOID
5120  if ((found_first_old_seg_node && !found_last_old_seg_node) ||
5121  (!found_first_old_seg_node && found_last_old_seg_node))
5122  {
5123  std::stringstream error_message;
5124  error_message
5125  << "Working with boundary (" << b << ").\nOnly the first node or "
5126  << "the last node of the old segment (" << old_is << ") was\n"
5127  << "found. Both, first and last node should have been found in "
5128  << "the same segment!!!.\n"
5129  << "Found first seg node:" << found_first_old_seg_node << "\n"
5130  << "Found last seg node:" << found_last_old_seg_node << "\n\n";
5131  throw OomphLibError(error_message.str(),
5132  "TriangleMesh::re_assign_initial_zeta_values_"
5133  "for_internal_boundary()",
5134  OOMPH_EXCEPTION_LOCATION);
5135  }
5136 #endif
5137 
5138  } // if (!done_segment[is])
5139  } // for (is < nsegments)
5140  } // for (old_is < old_nsegments)
5141 
5142  // For those segments not identified set dummy values, the boundary
5143  // coordinates should be corrected at the synchronisation stage
5144 
5145  // loop over the new segments and check if there not identified
5146  // segments
5147  for (unsigned is = 0; is < nsegments; is++)
5148  {
5149  // Was the segment identified
5150  if (!done_segment[is])
5151  {
5152  // Get the first node of the current segment
5153  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
5154  // Number of nodes
5155  const unsigned nnod = first_seg_ele_pt->nnode();
5156 
5157  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
5158  if (is_inverted[first_seg_ele_pt])
5159  {
5160  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod - 1);
5161  }
5162 
5163  // Get the arclength for the first node
5164  const double segment_first_node_zeta =
5165  sorted_segment_node_arclength[is][0];
5166 
5167  // Get the node coordinates for the first node
5168  Vector<double> first_node_coord(2);
5169  for (unsigned i = 0; i < 2; i++)
5170  {
5171  first_node_coord[i] = first_seg_node_pt->x(i);
5172  }
5173 
5174  // Get the last node of the current segment
5175  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
5176  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod - 1);
5177  if (is_inverted[last_seg_ele_pt])
5178  {
5179  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
5180  }
5181 
5182  // Get the arclength for the last node
5183  const double segment_final_node_zeta = segment_arclength[is];
5184 
5185  // Get the node coordinates for the last node
5186  Vector<double> last_node_coord(2);
5187  for (unsigned i = 0; i < 2; i++)
5188  {
5189  last_node_coord[i] = last_seg_node_pt->x(i);
5190  }
5191 
5192  // Re-assign the initial node coordinates
5193  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
5194 
5195  // Check if the boundary has an associated GeomObject
5196  if (this->boundary_geom_object_pt(b) != 0)
5197  {
5198  // Assign the zeta values if the current segment has the
5199  // nodes of the old one
5200 
5201  // If we are in the same order then pass the values as
5202  // they are
5203  Boundary_segment_initial_zeta[b][is] = initial_zeta_segment[is];
5204 
5205  } // if (this->boundary_geom_object_pt(b)!=0)
5206  else
5207  {
5208  // Re-assign the initial arclength for the current segment
5209  Boundary_segment_initial_arclength[b][is] = segment_first_node_zeta;
5210 
5211  } // else if (this->boundary_geom_object_pt(b)!=0)
5212 
5213  // Re-assign the initial node coordinates
5214  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5215 
5216  // Check if the boundary has an associated GeomObject
5217  if (this->boundary_geom_object_pt(b) != 0)
5218  {
5219  // Assign the zeta values if the current segment has the
5220  // nodes of the old one
5221 
5222  // If we are in the same order then pass the values as
5223  // they are
5224  Boundary_segment_final_zeta[b][is] = final_zeta_segment[is];
5225 
5226  } // if (this->boundary_geom_object_pt(b)!=0)
5227  else
5228  {
5229  // Re-assign the final arclength for the current segment
5230  Boundary_segment_final_arclength[b][is] = segment_final_node_zeta;
5231 
5232  } // else if (this->boundary_geom_object_pt(b)!=0)
5233 
5234  Boundary_segment_inverted[b][is] = 0;
5235 
5236  // Mark the segment as done
5237  done_segment[is] = true;
5238 
5239  // Increase the number of re-assigned segments
5240  re_assigned_segments++;
5241 
5242  } // if (!done_segment[is])
5243 
5244  } // for (is < nsegments)
5245 
5246 #ifdef PARANOID
5247  // Compare the number of new segments identified with the old segments
5248  if (re_assigned_segments != nsegments)
5249  {
5250  std::stringstream error_message;
5251  error_message << "Working with boundary (" << b
5252  << ").\nThe number of re-assigned "
5253  << "segments (" << re_assigned_segments
5254  << ") is different from the number\nof segments ("
5255  << nsegments << ")\n\n";
5256  throw OomphLibError(
5257  error_message.str(),
5258  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5259  OOMPH_EXCEPTION_LOCATION);
5260  } // if (re_assigned_segments != nsegments)
5261 #endif
5262 
5263  // Clean all the created face elements
5264  for (unsigned i = 0; i < nele; i++)
5265  {
5266  delete face_el_pt[i];
5267  face_el_pt[i] = 0;
5268  }
5269  }
5270 
5271  ///=====================================================================
5272  /// Select face elements from a given boundary. In case the we are
5273  /// dealing with an internal boundary we use a set of criterias to
5274  /// decide which of the two face elements should be used on represent
5275  /// the internal boundary. We return the face elements, halo or
5276  /// haloed on this processor that form the boundary. The caller method
5277  /// should be in charge of selecting nonhalo elements and deleting the face
5278  /// elements created by this method
5279  /// =====================================================================
5280  template<class ELEMENT>
5282  Vector<FiniteElement*>& face_ele_pt,
5283  const unsigned& b,
5284  bool& is_internal_boundary,
5285  std::map<FiniteElement*, FiniteElement*>& face_to_bulk_element_pt)
5286  {
5287  // Get the communicator of the mesh
5288  OomphCommunicator* comm_pt = this->communicator_pt();
5289 
5290  const unsigned my_rank = comm_pt->my_rank();
5291 
5292  // ------------------------------------------------------------------
5293  // 1) Get the face elements associated with the current boundary
5294  // ------------------------------------------------------------------
5295 
5296  // Temporary storage for face elements (do not take care of
5297  // repeated face elements)
5298  Vector<FiniteElement*> tmp_face_ele_pt;
5299 
5300  const unsigned nregions = this->nregion();
5301 
5302  // If there is more than one region then only use boundary
5303  // coordinates from the bulk side (region 0)
5304  if (nregions > 1)
5305  {
5306  for (unsigned ir = 0; ir < nregions; ir++)
5307  {
5308  const unsigned region_id =
5309  static_cast<unsigned>(this->Region_attribute[ir]);
5310 
5311  // Loop over all elements on boundaries in region -ir-
5312  const unsigned nele_in_region =
5313  this->nboundary_element_in_region(b, region_id);
5314 
5315  // Only bother to do anything else, if there are elements
5316  // associated with the boundary and the current region
5317  if (nele_in_region > 0)
5318  {
5319  // Loop over the bulk elements adjacent to boundary b
5320  for (unsigned e = 0; e < nele_in_region; e++)
5321  {
5322  // Get pointer to the bulk element that is adjacent
5323  // to boundary b
5324  FiniteElement* bulk_ele_pt =
5325  this->boundary_element_in_region_pt(b, region_id, e);
5326 
5327  // Get the index of the face of element e along
5328  // boundary b
5329  int face_index =
5330  this->face_index_at_boundary_in_region(b, region_id, e);
5331 
5332  // Create the face element
5333  FiniteElement* tmp_face_el_pt =
5334  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5335 
5336  // Associated the face element with the bulk
5337  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5338 
5339  // ... and add it to the tmp storage for all the
5340  // face elements, do not take care for repeated
5341  // ones (at the moment)
5342  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5343 
5344  } // for (e < nele_in_region)
5345 
5346  } // if (nele_in_region > 0)
5347 
5348  } // for (ir < n_regions)
5349 
5350  } // if (n_regions > 1)
5351 
5352  // Otherwise it's just the normal boundary functions
5353  else
5354  {
5355  // Loop over all elements on boundaries
5356  const unsigned nbound_ele = this->nboundary_element(b);
5357 
5358  // Only bother to do anything else, if there are elements
5359  if (nbound_ele > 0)
5360  {
5361  // Loop over the bulk elements adjacent to boundary b
5362  for (unsigned e = 0; e < nbound_ele; e++)
5363  {
5364  // Get pointer to the bulk element that is adjacent to
5365  // boundary b
5366  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5367 
5368  // Get the index of the face of element e along
5369  // boundary b
5370  int face_index = this->face_index_at_boundary(b, e);
5371 
5372  // Create the face element
5373  FiniteElement* tmp_face_el_pt =
5374  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5375 
5376  // Associated the face element with the bulk
5377  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5378 
5379  // ... and add it to the tmp storage for all the face
5380  // elements, do not care for repeated ones (at the
5381  // moment)
5382  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5383 
5384  } // (e < nbound_ele)
5385 
5386  } // (nbound_ele > 0)
5387 
5388  } // else (n_regions > 1)
5389 
5390  // map to know which face element has been already done
5391  std::map<FiniteElement*, bool> done_face;
5392 
5393  // Set the flag to indicate if we are working with an internal
5394  // boundary
5395  is_internal_boundary = false;
5396 
5397  // Free the memory of the elements in this container (only used
5398  // when working with internal boundaries)
5399  Vector<FiniteElement*> free_memory_face_ele_pt;
5400 
5401  // Get the number of face elements in the boundary (including
5402  // repeated)
5403  const unsigned n_tmp_face_ele = tmp_face_ele_pt.size();
5404  for (unsigned ie = 0; ie < n_tmp_face_ele; ie++)
5405  {
5406  // Get the possible main element
5407  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5408  if (!done_face[main_face_ele_pt])
5409  {
5410  // Mark the face element as done
5411  done_face[main_face_ele_pt] = true;
5412  // Get the number of nodes for the face element
5413  const unsigned nnodes = main_face_ele_pt->nnode();
5414  // Get the first and last node of the main face element
5415  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5416  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes - 1);
5417  // Look for the other side face element (we can start from
5418  // the next one, all previous face elements have been
5419  // already identified with its other side face)
5420  for (unsigned iie = ie + 1; iie < n_tmp_face_ele; iie++)
5421  {
5422  // Get the possible dependant element
5423  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5424  if (!done_face[dependant_face_ele_pt])
5425  {
5426  // Get the first and last node of the dependant
5427  // face element
5428  Node* dependant_first_node_pt = dependant_face_ele_pt->node_pt(0);
5429  Node* dependant_last_node_pt =
5430  dependant_face_ele_pt->node_pt(nnodes - 1);
5431  // Check if the nodes at the ends of both face
5432  // elements match (also check the reversed case)
5433  if (((dependant_first_node_pt == main_first_node_pt) &&
5434  (dependant_last_node_pt == main_last_node_pt)) ||
5435  ((dependant_first_node_pt == main_last_node_pt) &&
5436  (dependant_last_node_pt == main_first_node_pt)))
5437  {
5438  // Set the flag to indicate we are working with an
5439  // internal boundary
5440  is_internal_boundary = true;
5441  // Mark the face element as done
5442  done_face[dependant_face_ele_pt] = true;
5443 
5444  // Now choose which face element will be used
5445  // as the main element. We get the processor in
5446  // charge of the element and choose the one
5447  // with the highest processor in charge or the
5448  // bottom-left bulk element in case the both
5449  // faces are on the same processor
5450 
5451  // Get the bulk element for each face element
5452  // (the main and the dependant face element)
5453  FiniteElement* main_bulk_ele_pt =
5454  face_to_bulk_element_pt[main_face_ele_pt];
5455  FiniteElement* dependant_bulk_ele_pt =
5456  face_to_bulk_element_pt[dependant_face_ele_pt];
5457 
5458  // Get the processor in charge for each bulk
5459  // element
5460  int processor_in_charge_main_bulk_ele =
5461  main_bulk_ele_pt->non_halo_proc_ID();
5462  int processor_in_charge_dependant_bulk_ele =
5463  dependant_bulk_ele_pt->non_halo_proc_ID();
5464 
5465  // If the processor in charge is negative the
5466  // element is not halo, therefore the processor
5467  // in charge is the current one
5468  if (processor_in_charge_main_bulk_ele < 0)
5469  {
5470  processor_in_charge_main_bulk_ele = static_cast<int>(my_rank);
5471  }
5472  if (processor_in_charge_dependant_bulk_ele < 0)
5473  {
5474  processor_in_charge_dependant_bulk_ele =
5475  static_cast<int>(my_rank);
5476  }
5477 
5478  // Flag to know if add the main or dependant
5479  // face element
5480  bool add_main_face_element = true;
5481  if (processor_in_charge_dependant_bulk_ele >
5482  processor_in_charge_main_bulk_ele)
5483  {
5484  // Include the dependant element
5485  add_main_face_element = false;
5486  }
5487  else if (processor_in_charge_main_bulk_ele ==
5488  processor_in_charge_dependant_bulk_ele)
5489  {
5490  // When the processor in charge for both
5491  // elements is the same then use the
5492  // bottom-left criteria on the bulk
5493  // elements to choose the main face element
5494  Vector<double> main_ele_coordinates(2);
5495  Vector<double> dependant_ele_coordinates(2);
5496  // Get the number of nodes on the bulk
5497  // elements
5498  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5499  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5500  {
5501  for (unsigned idim = 0; idim < 2; idim++)
5502  {
5503  main_ele_coordinates[idim] +=
5504  main_bulk_ele_pt->node_pt(inode)->x(idim);
5505  dependant_ele_coordinates[idim] +=
5506  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5507  } // (idim < 2)
5508 
5509  } // (inode < n_bulk_nodes)
5510 
5511  // Get the average of the nodes coordinates
5512  for (unsigned idim = 0; idim < 2; idim++)
5513  {
5514  main_ele_coordinates[idim] /= (double)n_bulk_nodes;
5515  dependant_ele_coordinates[idim] /= (double)n_bulk_nodes;
5516  }
5517 
5518  // Once we know the average coordinates for
5519  // each element then we choose the one with
5520  // the bottom-left averaged coordinates
5521  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5522  {
5523  add_main_face_element = false;
5524  }
5525  else if (dependant_ele_coordinates[1] ==
5526  main_ele_coordinates[1])
5527  {
5528  // The left-most element
5529  if (dependant_ele_coordinates[0] < main_ele_coordinates[0])
5530  {
5531  add_main_face_element = false;
5532  }
5533  }
5534  } // else -- The processor in charge is the
5535  // same for both elements
5536 
5537  if (add_main_face_element)
5538  {
5539  // Add the main face element to the storage
5540  // so we get the halo and haloed nodes from
5541  // it
5542  face_ele_pt.push_back(main_face_ele_pt);
5543  // Mark the dependat face element to free
5544  // its memory
5545  free_memory_face_ele_pt.push_back(dependant_face_ele_pt);
5546  }
5547  else
5548  {
5549  // Add the dependant face element to the
5550  // storage so we get the halo and haloed
5551  // nodes from it
5552  face_ele_pt.push_back(dependant_face_ele_pt);
5553  // Mark the main face element to free its
5554  // memory
5555  free_memory_face_ele_pt.push_back(main_face_ele_pt);
5556  }
5557 
5558  // Break the for to look for the next face
5559  // element
5560  break;
5561 
5562  } // if -- matching of nodes from main ele and
5563  // dependant ele
5564 
5565  } // if (!done_face[dependant_face_ele_pt])
5566 
5567  } // for (iie < n_tmp_face_ele)
5568 
5569  } // if (!done_face[main_face_ele_pt])
5570 
5571  } // for (ie < n_tmp_face_ele)
5572 
5573  // Are there any face element to free its memory
5574  const unsigned n_free_face_ele = free_memory_face_ele_pt.size();
5575  if (n_free_face_ele == 0)
5576  {
5577  // If there is not face elements to free memory that means that
5578  // we are not working with an internal boundary, therefore copy
5579  // all the element from the tmp face elements into the face
5580  // elements container
5581 
5582  // Resize the container
5583  face_ele_pt.resize(n_tmp_face_ele);
5584  // loop over the elements and copy them
5585  for (unsigned i = 0; i < n_tmp_face_ele; i++)
5586  {
5587  face_ele_pt[i] = tmp_face_ele_pt[i];
5588  } // for (i < n_tmp_face_ele)
5589 
5590  } // if (n_free_face_ele == 0)
5591  else
5592  {
5593  // ... otherwise free the memory of the indicated elements
5594  // loop over the elements to free its memory
5595  for (unsigned i = 0; i < n_free_face_ele; i++)
5596  {
5597  delete free_memory_face_ele_pt[i];
5598  free_memory_face_ele_pt[i] = 0;
5599  } // for (i < n_free_face_ele)
5600  }
5601  }
5602 
5603  ///========================================================================
5604  /// In charge of sinchronize the boundary coordinates for internal
5605  /// boundaries that were split as part of the distribution
5606  /// process. Called after setup_boundary_coordinates() for the
5607  /// original mesh only
5608  ///========================================================================
5609  template<class ELEMENT>
5611  const unsigned& b)
5612  {
5613  // ------------------------------------------------------------------
5614  // First: Get the face elements associated with the current boundary
5615  // ------------------------------------------------------------------
5616 
5617  // Get the communicator of the mesh
5618  OomphCommunicator* comm_pt = this->communicator_pt();
5619 
5620  const unsigned nproc = comm_pt->nproc();
5621  const unsigned my_rank = comm_pt->my_rank();
5622 
5623  // Temporary storage for face elements (do not take care of repeated
5624  // face elements)
5625  Vector<FiniteElement*> tmp_face_ele_pt;
5626 
5627  const unsigned nregions = this->nregion();
5628 
5629  // map to associate the face element to the bulk element, necessary
5630  // to get the processor in charge for the halo elements
5631  std::map<FiniteElement*, FiniteElement*> face_to_bulk_element_pt;
5632 
5633  // If there is more than one region then only use boundary
5634  // coordinates from the bulk side (region 0)
5635  if (nregions > 1)
5636  {
5637  for (unsigned ir = 0; ir < nregions; ir++)
5638  {
5639  const unsigned region_id =
5640  static_cast<unsigned>(this->Region_attribute[ir]);
5641 
5642  // Loop over all elements on boundaries in region -ir-
5643  const unsigned nele_in_region =
5644  this->nboundary_element_in_region(b, region_id);
5645 
5646  // Only bother to do anything else, if there are elements
5647  // associated with the boundary and the current region
5648  if (nele_in_region > 0)
5649  {
5650  // Loop over the bulk elements adjacent to boundary b
5651  for (unsigned e = 0; e < nele_in_region; e++)
5652  {
5653  // Get pointer to the bulk element that is adjacent to boundary b
5654  FiniteElement* bulk_ele_pt =
5655  this->boundary_element_in_region_pt(b, region_id, e);
5656 
5657  // Get the index of the face of element e along boundary b
5658  int face_index =
5659  this->face_index_at_boundary_in_region(b, region_id, e);
5660 
5661  // Create the face element
5662  FiniteElement* tmp_face_el_pt =
5663  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5664 
5665  // ... and add it to the tmp storage for all the face
5666  // elements, do not take care for repeated ones (at the
5667  // moment)
5668  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5669  // Create the map to know if the element is halo
5670  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5671 
5672  } // for (e < nele_in_region)
5673 
5674  } // if (nele_in_region > 0)
5675 
5676  } // for (ir < n_regions)
5677 
5678  } // if (n_regions > 1)
5679 
5680  // Otherwise it's just the normal boundary functions
5681  else
5682  {
5683  // Loop over all elements on boundaries
5684  const unsigned nbound_ele = this->nboundary_element(b);
5685 
5686  // Only bother to do anything else, if there are elements
5687  if (nbound_ele > 0)
5688  {
5689  // Loop over the bulk elements adjacent to boundary b
5690  for (unsigned e = 0; e < nbound_ele; e++)
5691  {
5692  // Get pointer to the bulk element that is adjacent to boundary b
5693  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5694 
5695  // Get the index of the face of element e along boundary b
5696  int face_index = this->face_index_at_boundary(b, e);
5697 
5698  // Create the face element
5699  FiniteElement* tmp_face_el_pt =
5700  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5701 
5702  // ... and add it to the tmp storage for all the face
5703  // elements, do not care for repeated ones (at the moment)
5704  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5705  // Create the map to know if the element is halo
5706  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5707 
5708  } // (e < nbound_ele)
5709 
5710  } // (nbound_ele > 0)
5711 
5712  } // else (n_regions > 1)
5713 
5714  // Temporary storage for one side face elements. In case we are
5715  // working with an internal boundary here we store only one of the
5716  // face elements that are at each side of the boundary
5717  Vector<FiniteElement*> face_ele_pt;
5718 
5719  // map to know which face element has been already done
5720  std::map<FiniteElement*, bool> done_face;
5721 
5722  // Flag to indicate if we are working with an internal boundary
5723  bool is_internal_boundary = false;
5724 
5725 #ifdef PARANOID
5726  // Flag to indicate if we are working with an internal boundary (paranoid)
5727  bool is_internal_boundary_paranoid = false;
5728 
5729  // Count the number of other side face elements found in case we are
5730  // working with an internal boundary
5731  unsigned nfound_face_elements = 0;
5732 #endif
5733 
5734  // Get the number of face elements in the boundary
5735  const unsigned nbound_ele = tmp_face_ele_pt.size();
5736  for (unsigned ie = 0; ie < nbound_ele; ie++)
5737  {
5738  // Get the possible main element
5739  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5740  if (!done_face[main_face_ele_pt])
5741  {
5742  // Mark the face element as done
5743  done_face[main_face_ele_pt] = true;
5744  // Get the number of nodes for the face element
5745  const unsigned nnodes = main_face_ele_pt->nnode();
5746  // Get the first and last node of the main face element
5747  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5748  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes - 1);
5749  // Look for the other side face element
5750  for (unsigned iie = ie + 1; iie < nbound_ele; iie++)
5751  {
5752  // Get the possible dependant element
5753  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5754  if (!done_face[dependant_face_ele_pt])
5755  {
5756  // Get the first and last node of the dependant face element
5757  Node* dependant_first_node_pt = dependant_face_ele_pt->node_pt(0);
5758  Node* dependant_last_node_pt =
5759  dependant_face_ele_pt->node_pt(nnodes - 1);
5760  // Check if the nodes at the ends of both face elements
5761  // match (also check the reversed case)
5762  if (((dependant_first_node_pt == main_first_node_pt) &&
5763  (dependant_last_node_pt == main_last_node_pt)) ||
5764  ((dependant_first_node_pt == main_last_node_pt) &&
5765  (dependant_last_node_pt == main_first_node_pt)))
5766  {
5767 #ifdef PARANOID
5768  // Increase the number of found face elements
5769  nfound_face_elements += 2;
5770 #endif
5771  // Set the flag to indicate we are working with an
5772  // internal boundary
5773  is_internal_boundary = true;
5774  // Mark the face element as done
5775  done_face[dependant_face_ele_pt] = true;
5776 
5777  // Now choose which face element will be used as the main
5778  // element. Use the same criteria as the compute segments
5779  // connectivity method (highest processor in charge or
5780  // bottom-left bulk element)
5781 
5782  // Get the bulk element for each face element (the main
5783  // and the dependant face element)
5784  FiniteElement* main_bulk_ele_pt =
5785  face_to_bulk_element_pt[main_face_ele_pt];
5786  FiniteElement* dependant_bulk_ele_pt =
5787  face_to_bulk_element_pt[dependant_face_ele_pt];
5788 
5789  // Get the processor in charge for each bulk element
5790  int processor_in_charge_main_bulk_ele =
5791  main_bulk_ele_pt->non_halo_proc_ID();
5792  int processor_in_charge_dependant_bulk_ele =
5793  dependant_bulk_ele_pt->non_halo_proc_ID();
5794 
5795  // If the processor in charge is negative the element is
5796  // not halo, therefore the processor in charge is the
5797  // current one
5798  if (processor_in_charge_main_bulk_ele < 0)
5799  {
5800  processor_in_charge_main_bulk_ele = static_cast<int>(my_rank);
5801  }
5802  if (processor_in_charge_dependant_bulk_ele < 0)
5803  {
5804  processor_in_charge_dependant_bulk_ele =
5805  static_cast<int>(my_rank);
5806  }
5807 
5808  // Flag to know if add the main or dependant face element
5809  bool add_main_face_element = true;
5810  if (processor_in_charge_dependant_bulk_ele >
5811  processor_in_charge_main_bulk_ele)
5812  {
5813  // Include the dependant element
5814  add_main_face_element = false;
5815  }
5816  else if (processor_in_charge_main_bulk_ele ==
5817  processor_in_charge_dependant_bulk_ele)
5818  {
5819  // When the processor in charge for both elements is the same
5820  // then use the bottom-left criteria on the bulk elements to
5821  // choose the main face element
5822  Vector<double> main_ele_coordinates(2);
5823  Vector<double> dependant_ele_coordinates(2);
5824  // Get the number of nodes on the bulk elements
5825  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5826  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5827  {
5828  for (unsigned idim = 0; idim < 2; idim++)
5829  {
5830  main_ele_coordinates[idim] +=
5831  main_bulk_ele_pt->node_pt(inode)->x(idim);
5832  dependant_ele_coordinates[idim] +=
5833  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5834  } // (idim < 2)
5835  } // (inode < n_bulk_nodes)
5836 
5837  // Get the average of the nodes coordinates
5838  for (unsigned idim = 0; idim < 2; idim++)
5839  {
5840  main_ele_coordinates[idim] /= (double)n_bulk_nodes;
5841  dependant_ele_coordinates[idim] /= (double)n_bulk_nodes;
5842  }
5843 
5844  // Once we know the average coordinates for each element
5845  // then we choose the one with the bottom-left averaged
5846  // coordinates
5847  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5848  {
5849  add_main_face_element = false;
5850  }
5851  else if (dependant_ele_coordinates[1] ==
5852  main_ele_coordinates[1])
5853  {
5854  // The left-most element
5855  if (dependant_ele_coordinates[0] < main_ele_coordinates[0])
5856  {
5857  add_main_face_element = false;
5858  }
5859  }
5860  } // else -- The processor in charge is the same for both
5861  // elements
5862 
5863  if (add_main_face_element)
5864  {
5865  // Add the main face element to the storage so we get
5866  // the halo and haloed nodes from these face element
5867  face_ele_pt.push_back(main_face_ele_pt);
5868  }
5869  else
5870  {
5871  // Add the main face element to the storage so we get
5872  // the halo and haloed nodes from these face element
5873  face_ele_pt.push_back(dependant_face_ele_pt);
5874  }
5875 
5876  // Break the for to look for the next face element
5877  break;
5878 
5879  } // if -- matching of nodes from main ele and dependant ele
5880  } // if (!done_face[dependant_face_ele_pt])
5881  } // for (iie < nbound_ele)
5882  } // if (!done_face[main_face_ele_pt])
5883  } // for (ie < nbound_ele)
5884 
5885  // Get the number of face elements
5886  const unsigned nface_ele = face_ele_pt.size();
5887 
5888 #ifdef PARANOID
5889  // Check if we are working with an internal open curve. First check
5890  // if there are elements, in a distributed approach they may be no
5891  // elements associated to the boundary
5892  if (nbound_ele > 0 && nfound_face_elements == nbound_ele)
5893  {
5894  is_internal_boundary_paranoid = true;
5895  }
5896 
5897  if (nbound_ele > 0 && is_internal_boundary_paranoid &&
5898  nbound_ele != nface_ele * 2)
5899  {
5900  std::ostringstream error_message;
5901  error_message
5902  << "The info. to perform the synchronisation of the boundary "
5903  << "coordinates was not completely established\n"
5904  << "In this case it was the number of non repeated boundary elements\n"
5905  << "Number of boundary elements: (" << nbound_ele << ")\n"
5906  << "Number of nonrepeated boundary elements: (" << nface_ele << ")\n";
5907  throw OomphLibError(error_message.str(),
5908  "TriangleMesh::synchronize_boundary_coordinates()",
5909  OOMPH_EXCEPTION_LOCATION);
5910  }
5911 #endif
5912 
5913  // ----------------------------------------------------------------
5914  // Second: Identify the halo face elements
5915  // ----------------------------------------------------------------
5916 
5917  // A flag vector to mark those face elements that are considered as
5918  // halo in the current processor
5919  std::vector<bool> is_halo_face_element(nface_ele, false);
5920 
5921  // Count the total number of non halo face elements
5922  unsigned nnon_halo_face_elements = 0;
5923 
5924  for (unsigned ie = 0; ie < nface_ele; ie++)
5925  {
5926  FiniteElement* face_el_pt = face_ele_pt[ie];
5927  // Get the bulk element
5928  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_el_pt];
5929  // Check if the bulk element is halo
5930  if (!tmp_bulk_ele_pt->is_halo())
5931  {
5932  is_halo_face_element[ie] = false;
5933  nnon_halo_face_elements++;
5934  }
5935  else
5936  {
5937  // Mark the face element as halo
5938  is_halo_face_element[ie] = true;
5939  }
5940  } // for (ie < nface_ele)
5941 
5942  // -----------------------------------------------------------------
5943  // Third: Go through the face elements and get the nodes from the
5944  // elements. The boundary coordinate from each node is sent to its
5945  // processor in charge, then that processor will be responsible to
5946  // send the bound coordinate to all the processors that have a halo
5947  // representation of the node
5948  // -----------------------------------------------------------------
5949 
5950  // A map to know which nodes are already done
5951  std::map<Node*, bool> done_node;
5952 
5953  // The storage for the halo nodes on face elements in this processor
5954  // with other processors
5955  Vector<Vector<Node*>> face_halo_node_pt(nproc);
5956 
5957  // The storage for the ids of the halo nodes on face elements in
5958  // this processor with other processors
5959  Vector<Vector<unsigned>> face_halo_node_id(nproc);
5960 
5961  // The storage for the haloed nodes on face elements in this
5962  // processor with other processors
5963  Vector<Vector<Node*>> face_haloed_node_pt(nproc);
5964 
5965  // The storage for the ids of the haloed nodes on face elements in
5966  // this processor with other processors
5967  Vector<Vector<unsigned>> face_haloed_node_id(nproc);
5968 
5969  // A map to know which nodes are face nodes and the processor in
5970  // charge is the current one
5971  std::map<Node*, bool> done_haloed_face_node;
5972 
5973  // Go through all the face elements
5974  for (unsigned iface = 0; iface < nface_ele; iface++)
5975  {
5976  // Only work with the non halo face elements
5977  if (!is_halo_face_element[iface])
5978  {
5979  // Get the face element
5980  FiniteElement* ele_face_pt = face_ele_pt[iface];
5981  // The number of nodes of the face elements
5982  const unsigned nnodes = ele_face_pt->nnode();
5983  // Go through all the nodes in the face element
5984  for (unsigned in = 0; in < nnodes; in++)
5985  {
5986  Node* face_node_pt = ele_face_pt->node_pt(in);
5987  // Check if node is done
5988  if (!done_node[face_node_pt])
5989  {
5990  // Mark the node as done
5991  done_node[face_node_pt] = true;
5992  // First check if the node is halo
5993  if (face_node_pt->is_halo())
5994  {
5995  // Get the processor in charge for the current node
5996  int int_nonhalo_ID = face_node_pt->non_halo_proc_ID();
5997 #ifdef PARANOID
5998  if (int_nonhalo_ID < 0)
5999  {
6000  std::ostringstream error_message;
6001  error_message
6002  << "The node was marked to be halo but the processor in "
6003  << "charge was found to be -1\n\n";
6004  throw OomphLibError(
6005  error_message.str(),
6006  "TriangleMesh::synchronize_boundary_coordinates()",
6007  OOMPH_EXCEPTION_LOCATION);
6008  }
6009 #endif
6010  const unsigned ip = static_cast<unsigned>(int_nonhalo_ID);
6011  // Add the node to the structure that holds the halo
6012  // nodes, the current processor will need to send the
6013  // info. to the processor in charge.
6014  face_halo_node_pt[ip].push_back(face_node_pt);
6015  // ... finally look for the halo id with the processor in
6016  // charge
6017 #ifdef PARANOID
6018  bool found_halo_node = false;
6019 #endif
6020  const unsigned nhalo_iproc = this->nhalo_node(ip);
6021  for (unsigned ihn = 0; ihn < nhalo_iproc; ihn++)
6022  {
6023  Node* compare_face_node_pt = this->halo_node_pt(ip, ihn);
6024  if (compare_face_node_pt == face_node_pt)
6025  {
6026  // Once found the id of the node with the processor
6027  // store the id in the proper storage
6028  face_halo_node_id[ip].push_back(ihn);
6029 #ifdef PARANOID
6030  // Set the flag to mark as found the halo node
6031  found_halo_node = true;
6032 #endif
6033  // Break the loop
6034  break;
6035  }
6036  } // for (ih < nhalo_iproc)
6037 #ifdef PARANOID
6038  if (!found_halo_node)
6039  {
6040  std::ostringstream error_message;
6041  error_message
6042  << "The halo id of the current node: (" << face_node_pt->x(0)
6043  << ", " << face_node_pt->x(1) << ") with processor (" << ip
6044  << ") was not found!!!\n\n";
6045  throw OomphLibError(
6046  error_message.str(),
6047  "TriangleMesh::synchronize_boundary_coordinates()",
6048  OOMPH_EXCEPTION_LOCATION);
6049  }
6050 #endif
6051  } // if (face_node_pt->is_halo())
6052  // If the node is not halo then it could be haloed. If that
6053  // is the case then store the processors at which the node
6054  // is haloed and its id. The info. of these nodes will be
6055  // sent to all the processors with a halo counterpart
6056  else
6057  {
6058  for (unsigned ip = 0; ip < nproc; ip++)
6059  {
6060  // Only work with processors different that the current one
6061  if (ip != my_rank)
6062  {
6063  // If the node is found to be haloed with the "ip"
6064  // processor then save the haloed id in the storage.
6065  // The current processor needs to send info. to the
6066  // other processors to establish the boundary
6067  // coordinates
6068 
6069  // Get the number of haloed nodes with processor ip
6070  const unsigned nhaloed_iproc = this->nhaloed_node(ip);
6071  for (unsigned ihdn = 0; ihdn < nhaloed_iproc; ihdn++)
6072  {
6073  Node* compare_face_node_pt = this->haloed_node_pt(ip, ihdn);
6074  if (face_node_pt == compare_face_node_pt)
6075  {
6076  // Store the node on the haloed node vector for
6077  // the corresponding processor
6078  face_haloed_node_pt[ip].push_back(face_node_pt);
6079  // Now store the halo id of the node with the
6080  // current processor
6081  face_haloed_node_id[ip].push_back(ihdn);
6082  // Mark the node as haloed with other processors,
6083  // so we know the processor in charge is the
6084  // current one "my_rank".
6085  done_haloed_face_node[face_node_pt] = true;
6086  // Break looking in the current processor, look in
6087  // the next one
6088  break;
6089  } // if (face_node_pt == compare_face_node_pt)
6090  } // for (ihdn < nhaloed_node_iproc)
6091  } // if (ip != my_rank)
6092  } // for (ip < nproc)
6093  } // else (non halo node)
6094  } // if (!done_node[node_face_pt])
6095  } // for (in < nnodes)
6096  } // if (!is_halo_face_element[iface])
6097  } // for (iface < nface_ele)
6098 
6099  // -----------------------------------------------------------------
6100  // Fourth: Go through the halo nodes, package and send the
6101  // info. necessary to identify the face nodes in the processor in
6102  // charge. Identify the haloed nodes in the processor in charge and
6103  // establish the boundary coordinates, check if those nodes are
6104  // (already) marked as faced nodes, if that is the case then do not
6105  // establish the boundary coordinates but register them to send back
6106  // the info. to all the processors that have a halo representation
6107  // of the face node
6108  // -----------------------------------------------------------------
6109 
6110  // Go through all processors
6111  for (unsigned ip = 0; ip < nproc; ip++)
6112  {
6113  // Only work with processors different than the current one
6114  if (ip != my_rank)
6115  {
6116  const unsigned nhalo_face_nodes = face_halo_node_pt[ip].size();
6117 #ifdef PARANOID
6118  if (nhalo_face_nodes != face_halo_node_id[ip].size())
6119  {
6120  std::ostringstream error_message;
6121  error_message
6122  << "The number of found halo face nodes (" << nhalo_face_nodes
6123  << ") is different from the number of\nfound halo face ids ("
6124  << face_halo_node_id[ip].size() << ")!!!\n\n";
6125  throw OomphLibError(
6126  error_message.str(),
6127  "TriangleMesh::synchronize_boundary_coordinates()",
6128  OOMPH_EXCEPTION_LOCATION);
6129  }
6130 #endif
6131 
6132  // Container to send the info. related with the halo nodes to be
6133  // identified in the processors in charge
6134  Vector<unsigned> flat_unsigned_send_packed_data;
6135  Vector<double> flat_double_send_packed_data;
6136 
6137  // Go through the halo face nodes in the "ip" processor
6138  for (unsigned ihfn = 0; ihfn < nhalo_face_nodes; ihfn++)
6139  {
6140  // Get the "ihfn"-th face node with the "ip" processor
6141  Node* halo_face_node_pt = face_halo_node_pt[ip][ihfn];
6142  // Get the halo id with the "ip" processor
6143  const unsigned halo_id = face_halo_node_id[ip][ihfn];
6144  // Get the boundary coordinate of the node
6145  Vector<double> zeta(1);
6146  halo_face_node_pt->get_coordinates_on_boundary(b, zeta);
6147  // Store the info. in the containers
6148  flat_unsigned_send_packed_data.push_back(halo_id);
6149  flat_double_send_packed_data.push_back(zeta[0]);
6150  }
6151 
6152  // Send the info.
6153  MPI_Status status;
6154  MPI_Request request;
6155 
6156  // Processor to which send the info
6157  int send_proc = static_cast<int>(ip);
6158  // Processor from which receive the info
6159  int receive_proc = static_cast<int>(ip);
6160 
6161  // Storage to receive the info.
6162  Vector<unsigned> flat_unsigned_receive_packed_data;
6163  Vector<double> flat_double_receive_packed_data;
6164 
6165  // --------------
6166  // Unsigned data
6167  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6168  MPI_Isend(&nflat_unsigned_send,
6169  1,
6170  MPI_UNSIGNED,
6171  send_proc,
6172  1,
6173  comm_pt->mpi_comm(),
6174  &request);
6175 
6176  unsigned nflat_unsigned_receive = 0;
6177  MPI_Recv(&nflat_unsigned_receive,
6178  1,
6179  MPI_UNSIGNED,
6180  receive_proc,
6181  1,
6182  comm_pt->mpi_comm(),
6183  &status);
6184 
6185  MPI_Wait(&request, MPI_STATUS_IGNORE);
6186 
6187  if (nflat_unsigned_send != 0)
6188  {
6189  MPI_Isend(&flat_unsigned_send_packed_data[0],
6190  nflat_unsigned_send,
6191  MPI_UNSIGNED,
6192  send_proc,
6193  2,
6194  comm_pt->mpi_comm(),
6195  &request);
6196  }
6197 
6198  if (nflat_unsigned_receive != 0)
6199  {
6200  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6201  MPI_Recv(&flat_unsigned_receive_packed_data[0],
6202  nflat_unsigned_receive,
6203  MPI_UNSIGNED,
6204  receive_proc,
6205  2,
6206  comm_pt->mpi_comm(),
6207  &status);
6208  }
6209 
6210  if (nflat_unsigned_send != 0)
6211  {
6212  MPI_Wait(&request, MPI_STATUS_IGNORE);
6213  }
6214 
6215  // --------------
6216  // Double data
6217  unsigned nflat_double_send = flat_double_send_packed_data.size();
6218  MPI_Isend(&nflat_double_send,
6219  1,
6220  MPI_DOUBLE,
6221  send_proc,
6222  3,
6223  comm_pt->mpi_comm(),
6224  &request);
6225 
6226  unsigned nflat_double_receive = 0;
6227  MPI_Recv(&nflat_double_receive,
6228  1,
6229  MPI_DOUBLE,
6230  receive_proc,
6231  3,
6232  comm_pt->mpi_comm(),
6233  &status);
6234 
6235  MPI_Wait(&request, MPI_STATUS_IGNORE);
6236 
6237  if (nflat_double_send != 0)
6238  {
6239  MPI_Isend(&flat_double_send_packed_data[0],
6240  nflat_double_send,
6241  MPI_DOUBLE,
6242  send_proc,
6243  4,
6244  comm_pt->mpi_comm(),
6245  &request);
6246  }
6247 
6248  if (nflat_double_receive != 0)
6249  {
6250  flat_double_receive_packed_data.resize(nflat_double_receive);
6251  MPI_Recv(&flat_double_receive_packed_data[0],
6252  nflat_double_receive,
6253  MPI_DOUBLE,
6254  receive_proc,
6255  4,
6256  comm_pt->mpi_comm(),
6257  &status);
6258  }
6259 
6260  if (nflat_double_send != 0)
6261  {
6262  MPI_Wait(&request, MPI_STATUS_IGNORE);
6263  }
6264  // --------------
6265 
6266 #ifdef PARANOID
6267  if (nflat_unsigned_receive != nflat_double_receive)
6268  {
6269  std::ostringstream error_message;
6270  error_message << "The number of unsigned received data ("
6271  << nflat_unsigned_receive << ") is different from the "
6272  << "number\nof double received data ("
6273  << nflat_double_receive << ")!!!\n\n";
6274  throw OomphLibError(
6275  error_message.str(),
6276  "TriangleMesh::synchronize_boundary_coordinates()",
6277  OOMPH_EXCEPTION_LOCATION);
6278  }
6279 #endif
6280 
6281  // With the received info. establish the boundary coordinates
6282  // for the face nodes that this processor is in charge (haloed
6283  // nodes)
6284  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6285  iflat_packed++)
6286  {
6287  // Get the haloed id for the node
6288  const unsigned haloed_id =
6289  flat_unsigned_receive_packed_data[iflat_packed];
6290  // Get the boundary coordinates
6291  Vector<double> zeta(1);
6292  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6293 
6294  // Get the haloed node
6295  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6296 
6297  // If the node has already set the boundary coordinates then
6298  // do not establish it. This is the case for the nodes that
6299  // lie on the boundary, for those nodes not identified on the
6300  // boundary since no elements lie on the boundary but the node
6301  // is on the boundary (a corner of an element lies on the
6302  // boundary) set boundary coordinates and register them to
6303  // send their info. to the processors with a halo counterpart
6304 
6305  // If the node is not haloed face in the procesor in charge
6306  // then set the boundary coordinates and register the node to
6307  // send back the boundary coordinates to the processors with a
6308  // halo counterpart
6309  if (!done_haloed_face_node[haloed_face_node_pt])
6310  {
6311  // Establish the boundary coordinates
6312  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6313 
6314  // Look in all processors where the node could be halo
6315  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6316  {
6317  // Only work with processors different than the current one
6318  if (iiproc != my_rank)
6319  {
6320  // Get the number of haloed nodes with processor iiproc
6321  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6322  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6323  {
6324  Node* compare_haloed_node_pt =
6325  this->haloed_node_pt(iiproc, ihdn);
6326  if (haloed_face_node_pt == compare_haloed_node_pt)
6327  {
6328  // Store the node on the haloed node vector for the
6329  // corresponding processor
6330  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6331  // Now store the halo id of the node with the current
6332  // processor
6333  face_haloed_node_id[iiproc].push_back(ihdn);
6334  // Break searching in the current processor, search in
6335  // the next one
6336  break;
6337  } // if (haloed_face_node_pt==compare_haloed_face_node_pt)
6338  } // for (ihdn < nhaloed_node_iproc)
6339  } // if (iiproc != my_rank)
6340  } // for (iiproc < nproc)
6341  } // if (!done_haloed_face_node[haloed_face_node_pt])
6342  } // for (iflat_packed < nflat_unsigned_receive)
6343  } // if (ip != my_rank)
6344  } // for (ip < nproc)
6345 
6346  // -----------------------------------------------------------------
6347  // Fifth: The boundary coordinates have been established in the
6348  // processors in charge of the nodes. Now each processor send back
6349  // the boundary coordinates to all the processors where there is a
6350  // halo representation of the node
6351  // -----------------------------------------------------------------
6352 
6353  // Go through all processors
6354  for (unsigned ip = 0; ip < nproc; ip++)
6355  {
6356  // Only work with processors different than the current one
6357  if (ip != my_rank)
6358  {
6359  // Container to send the info. of the haloed nodes to all the
6360  // processors
6361  Vector<unsigned> flat_unsigned_send_packed_data;
6362  Vector<double> flat_double_send_packed_data;
6363 
6364  // Get the total number of haloed face nodes with the "ip"
6365  // processor
6366  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6367  // Go through the haloed face nodes in the "ip" processor
6368  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6369  {
6370  // Get the "ihdfn"-th face node with the "ip" processor
6371  Node* haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6372  // Get the haloed id with the "ip" processor
6373  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6374  // Get the boundary coordinate of the node
6375  Vector<double> zeta(1);
6376  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6377  // Store the info. in the containers
6378  flat_unsigned_send_packed_data.push_back(haloed_id);
6379  flat_double_send_packed_data.push_back(zeta[0]);
6380  }
6381 
6382  // Send the info.
6383  MPI_Status status;
6384  MPI_Request request;
6385 
6386  // Processor to which send the info
6387  int send_proc = static_cast<int>(ip);
6388  // Processor from which receive the info
6389  int receive_proc = static_cast<int>(ip);
6390 
6391  // Storage to receive the info.
6392  Vector<unsigned> flat_unsigned_receive_packed_data;
6393  Vector<double> flat_double_receive_packed_data;
6394 
6395  // --------------
6396  // Unsigned data
6397  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6398  MPI_Isend(&nflat_unsigned_send,
6399  1,
6400  MPI_UNSIGNED,
6401  send_proc,
6402  1,
6403  comm_pt->mpi_comm(),
6404  &request);
6405 
6406  unsigned nflat_unsigned_receive = 0;
6407  MPI_Recv(&nflat_unsigned_receive,
6408  1,
6409  MPI_UNSIGNED,
6410  receive_proc,
6411  1,
6412  comm_pt->mpi_comm(),
6413  &status);
6414 
6415  MPI_Wait(&request, MPI_STATUS_IGNORE);
6416 
6417  if (nflat_unsigned_send != 0)
6418  {
6419  MPI_Isend(&flat_unsigned_send_packed_data[0],
6420  nflat_unsigned_send,
6421  MPI_UNSIGNED,
6422  send_proc,
6423  2,
6424  comm_pt->mpi_comm(),
6425  &request);
6426  }
6427 
6428  if (nflat_unsigned_receive != 0)
6429  {
6430  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6431  MPI_Recv(&flat_unsigned_receive_packed_data[0],
6432  nflat_unsigned_receive,
6433  MPI_UNSIGNED,
6434  receive_proc,
6435  2,
6436  comm_pt->mpi_comm(),
6437  &status);
6438  }
6439 
6440  if (nflat_unsigned_send != 0)
6441  {
6442  MPI_Wait(&request, MPI_STATUS_IGNORE);
6443  }
6444 
6445  // --------------
6446  // Double data
6447  unsigned nflat_double_send = flat_double_send_packed_data.size();
6448  MPI_Isend(&nflat_double_send,
6449  1,
6450  MPI_DOUBLE,
6451  send_proc,
6452  3,
6453  comm_pt->mpi_comm(),
6454  &request);
6455 
6456  unsigned nflat_double_receive = 0;
6457  MPI_Recv(&nflat_double_receive,
6458  1,
6459  MPI_DOUBLE,
6460  receive_proc,
6461  3,
6462  comm_pt->mpi_comm(),
6463  &status);
6464 
6465  MPI_Wait(&request, MPI_STATUS_IGNORE);
6466 
6467  if (nflat_double_send != 0)
6468  {
6469  MPI_Isend(&flat_double_send_packed_data[0],
6470  nflat_double_send,
6471  MPI_DOUBLE,
6472  send_proc,
6473  4,
6474  comm_pt->mpi_comm(),
6475  &request);
6476  }
6477 
6478  if (nflat_double_receive != 0)
6479  {
6480  flat_double_receive_packed_data.resize(nflat_double_receive);
6481  MPI_Recv(&flat_double_receive_packed_data[0],
6482  nflat_double_receive,
6483  MPI_DOUBLE,
6484  receive_proc,
6485  4,
6486  comm_pt->mpi_comm(),
6487  &status);
6488  }
6489 
6490  if (nflat_double_send != 0)
6491  {
6492  MPI_Wait(&request, MPI_STATUS_IGNORE);
6493  }
6494  // --------------
6495 
6496 #ifdef PARANOID
6497  if (nflat_unsigned_receive != nflat_double_receive)
6498  {
6499  std::ostringstream error_message;
6500  error_message << "The number of unsigned received data ("
6501  << nflat_unsigned_receive << ") is different from the "
6502  << "number\nof double received data ("
6503  << nflat_double_receive << ")!!!\n\n";
6504  throw OomphLibError(
6505  error_message.str(),
6506  "TriangleMesh::synchronize_boundary_coordinates()",
6507  OOMPH_EXCEPTION_LOCATION);
6508  }
6509 #endif
6510 
6511  // With the received info. establish the boundary coordinates
6512  // received for the face nodes that this processor is not in
6513  // charge (halo nodes)
6514  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6515  iflat_packed++)
6516  {
6517  // Get the halo id for the node
6518  const unsigned halo_id =
6519  flat_unsigned_receive_packed_data[iflat_packed];
6520  // Get the boundary coordinates
6521  Vector<double> zeta(1);
6522  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6523 
6524  // Get the halo node
6525  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6526 
6527  // It could be possible that the node has been already
6528  // established boundary coordinates since it is a halo face
6529  // node. However, for those elements not on the boundary, but
6530  // having a corner node on the boundary this procedure will
6531  // establish boundary coordinates for those nodes
6532 
6533  // this->add_boundary_node(b, halo_face_node_pt);
6534 
6535  // Establish the boundary coordinates
6536  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6537  } // for (iflat_packed < nflat_unsigned_receive)
6538  } // if (ip != my_rank)
6539  } // for (ip < nproc)
6540 
6541  // Clean all the created face elements
6542  for (unsigned ie = 0; ie < nbound_ele; ie++)
6543  {
6544  delete tmp_face_ele_pt[ie];
6545  tmp_face_ele_pt[ie] = 0;
6546  }
6547 
6548  // Now get a new face mesh representation and fill the data for those
6549  // processors with halo segments
6550  if (is_internal_boundary)
6551  {
6552  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6553  }
6554  }
6555 
6556  //======================================================================
6557  /// \short Re-assign the boundary segments initial zeta (arclength)
6558  /// for those internal boundaries that were splited during the
6559  /// distribution process (only apply for internal boundaries that
6560  /// have one face element at each side of the boundary)
6561  //======================================================================
6562  template<class ELEMENT>
6565  const unsigned& b)
6566  {
6567  // ------------------------------------------------------------------
6568  // First: Get the face elements associated with the current boundary
6569  // Only include nonhalo face elements
6570  // ------------------------------------------------------------------
6571  // Temporary storage for face elements
6572  Vector<FiniteElement*> face_el_pt;
6573 
6574  // Temporary storage for the number of elements adjacent to the
6575  // boundary
6576  unsigned nele = 0;
6577 
6578  // Temporary storage for elements adjacent to the boundary that have
6579  // a common edge (related with internal boundaries)
6580  unsigned n_repeated_ele = 0;
6581 
6582  const unsigned n_regions = this->nregion();
6583 
6584  // Temporary storage for already done nodes
6585  Vector<std::pair<Node*, Node*>> done_nodes_pt;
6586 
6587  // If there is more than one region then only use boundary
6588  // coordinates from the bulk side (region 0)
6589  if (n_regions > 1)
6590  {
6591  for (unsigned rr = 0; rr < n_regions; rr++)
6592  {
6593  const unsigned region_id =
6594  static_cast<unsigned>(this->Region_attribute[rr]);
6595 
6596  // Loop over all elements on boundaries in region i_r
6597  const unsigned nel_in_region =
6598  this->nboundary_element_in_region(b, region_id);
6599 
6600  unsigned nel_repetead_in_region = 0;
6601 
6602  // Only bother to do anything else, if there are elements
6603  // associated with the boundary and the current region
6604  if (nel_in_region > 0)
6605  {
6606  bool repeated = false;
6607 
6608  // Loop over the bulk elements adjacent to boundary b
6609  for (unsigned e = 0; e < nel_in_region; e++)
6610  {
6611  // Get pointer to the bulk element that is adjacent to
6612  // boundary b
6613  FiniteElement* bulk_elem_pt =
6614  this->boundary_element_in_region_pt(b, region_id, e);
6615 
6616  // Remember only to work with nonhalo elements
6617  if (bulk_elem_pt->is_halo())
6618  {
6619  n_repeated_ele++;
6620  continue;
6621  }
6622 
6623  // Find the index of the face of element e along boundary b
6624  int face_index =
6625  this->face_index_at_boundary_in_region(b, region_id, e);
6626 
6627  // Before adding the new element we need to be sure that the
6628  // edge that this element represent has not been already
6629  // added
6630  FiniteElement* tmp_ele_pt =
6631  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6632 
6633  const unsigned n_nodes = tmp_ele_pt->nnode();
6634 
6635  std::pair<Node*, Node*> tmp_pair = std::make_pair(
6636  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
6637 
6638  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
6639  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
6640 
6641  // Search for repeated nodes
6642  const unsigned n_done_nodes = done_nodes_pt.size();
6643  for (unsigned l = 0; l < n_done_nodes; l++)
6644  {
6645  if (tmp_pair == done_nodes_pt[l] ||
6646  tmp_pair_inverse == done_nodes_pt[l])
6647  {
6648  nel_repetead_in_region++;
6649  repeated = true;
6650  break;
6651  }
6652  }
6653 
6654  // Create new face element
6655  if (!repeated)
6656  {
6657  // Add the pair of nodes (edge) to the node dones
6658  done_nodes_pt.push_back(tmp_pair);
6659  // Add the element to the face elements
6660  face_el_pt.push_back(tmp_ele_pt);
6661  }
6662  else
6663  {
6664  // Clean up
6665  delete tmp_ele_pt;
6666  tmp_ele_pt = 0;
6667  }
6668 
6669  // Re-start
6670  repeated = false;
6671 
6672  } // for nel
6673 
6674  nele += nel_in_region;
6675 
6676  n_repeated_ele += nel_repetead_in_region;
6677 
6678  } // if (nel_in_region > 0)
6679  } // for (rr < n_regions)
6680  } // if (n_regions > 1)
6681  // Otherwise it's just the normal boundary functions
6682  else
6683  {
6684  // Loop over all elements on boundaries
6685  nele = this->nboundary_element(b);
6686 
6687  // Only bother to do anything else, if there are elements
6688  if (nele > 0)
6689  {
6690  // Check for repeated ones
6691  bool repeated = false;
6692 
6693  // Loop over the bulk elements adjacent to boundary b
6694  for (unsigned e = 0; e < nele; e++)
6695  {
6696  // Get pointer to the bulk element that is adjacent to
6697  // boundary b
6698  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6699 
6700  // Remember only to work with nonhalo elements
6701  if (bulk_elem_pt->is_halo())
6702  {
6703  n_repeated_ele++;
6704  // Skip the halo element
6705  continue;
6706  }
6707 
6708  // Find the index of the face of element e along boundary b
6709  int face_index = this->face_index_at_boundary(b, e);
6710 
6711  // Before adding the new element we need to be sure that the
6712  // edge that this element represents has not been already
6713  // added (only applies for internal boundaries)
6714  FiniteElement* tmp_ele_pt =
6715  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6716 
6717  const unsigned n_nodes = tmp_ele_pt->nnode();
6718 
6719  std::pair<Node*, Node*> tmp_pair = std::make_pair(
6720  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
6721 
6722  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
6723  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
6724 
6725  // Search for repeated nodes
6726  const unsigned n_done_nodes = done_nodes_pt.size();
6727  for (unsigned l = 0; l < n_done_nodes; l++)
6728  {
6729  if (tmp_pair == done_nodes_pt[l] ||
6730  tmp_pair_inverse == done_nodes_pt[l])
6731  {
6732  // Increase the number of repeated elements
6733  n_repeated_ele++;
6734  // Mark the element as repeated
6735  repeated = true;
6736  break;
6737  }
6738  }
6739 
6740  // Create new face element
6741  if (!repeated)
6742  {
6743  // Add the pair of nodes (edge) to the node dones
6744  done_nodes_pt.push_back(tmp_pair);
6745  // Add the element to the face elements
6746  face_el_pt.push_back(tmp_ele_pt);
6747  }
6748  else
6749  {
6750  // Free the repeated bulk element!!
6751  delete tmp_ele_pt;
6752  tmp_ele_pt = 0;
6753  }
6754 
6755  // Re-start
6756  repeated = false;
6757 
6758  } // for (e < nel)
6759  } // if (nel > 0)
6760 
6761  } // else (n_regions > 1)
6762 
6763  // Do not consider the repeated elements
6764  nele -= n_repeated_ele;
6765 
6766 #ifdef PARANOID
6767  if (nele != face_el_pt.size())
6768  {
6769  std::ostringstream error_message;
6770  error_message
6771  << "The independet counting of face elements (" << nele << ") for "
6772  << "boundary (" << b << ") is different\n"
6773  << "from the real number of face elements in the container ("
6774  << face_el_pt.size() << ")\n";
6775  //<< "Possible memory leak\n"
6776  throw OomphLibError(error_message.str(),
6777  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6778  "values_for_internal_boundary()",
6779  OOMPH_EXCEPTION_LOCATION);
6780  }
6781 #endif
6782 
6783  // ----------------------------------------------------------------
6784  // Second: Sort the face elements (to create segments), only
6785  // consider nonhalo elements
6786  // ----------------------------------------------------------------
6787 
6788  // Get the total number of nonhalo face elements
6789  const unsigned nnon_halo_face_elements = face_el_pt.size();
6790 
6791  // The vector of list to store the "segments" that compound the
6792  // boundary (segments may appear only in a distributed mesh)
6793  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
6794 
6795  // Number of already sorted face elements
6796  unsigned nsorted_face_elements = 0;
6797 
6798  // Keep track of who's done
6799  std::map<FiniteElement*, bool> done_el;
6800 
6801  // Keep track of which element is inverted
6802  std::map<FiniteElement*, bool> is_inverted;
6803 
6804  // Iterate until all possible segments have been created
6805  while (nsorted_face_elements < nnon_halo_face_elements)
6806  {
6807  // The ordered list of face elements (in a distributed mesh a
6808  // collection of contiguous face elements define a segment)
6809  std::list<FiniteElement*> sorted_el_pt;
6810 
6811 #ifdef PARANOID
6812  // Select an initial element for the segment
6813  bool found_initial_face_element = false;
6814 #endif
6815 
6816  FiniteElement* ele_face_pt = 0;
6817 
6818  unsigned iface = 0;
6819  for (iface = 0; iface < nele; iface++)
6820  {
6821  ele_face_pt = face_el_pt[iface];
6822  // If not done then take it as initial face element
6823  if (!done_el[ele_face_pt])
6824  {
6825 #ifdef PARANOID
6826  found_initial_face_element = true;
6827 #endif
6828  nsorted_face_elements++;
6829  iface++; // The next element number
6830  sorted_el_pt.push_back(ele_face_pt);
6831  // Mark as done
6832  done_el[ele_face_pt] = true;
6833  break;
6834  }
6835  } // for (iface < nele)
6836 
6837 #ifdef PARANOID
6838  if (!found_initial_face_element)
6839  {
6840  std::ostringstream error_message;
6841  error_message
6842  << "Could not find an initial face element for the current segment\n";
6843  // << "----- Possible memory leak -----\n";
6844  throw OomphLibError(error_message.str(),
6845  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6846  "values_for_internal_boundary()",
6847  OOMPH_EXCEPTION_LOCATION);
6848  }
6849 #endif
6850 
6851  // Number of nodes
6852  const unsigned nnod = ele_face_pt->nnode();
6853 
6854  // Left and rightmost nodes (the left and right nodes of the
6855  // current face element)
6856  Node* left_node_pt = ele_face_pt->node_pt(0);
6857  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6858 
6859  // Continue iterating if a new face element has been added to the
6860  // list
6861  bool face_element_added = false;
6862 
6863  // While a new face element has been added to the set of sorted
6864  // face elements then re-iterate
6865  do
6866  {
6867  // Start from the next face element since we have already added
6868  // the previous one as the initial face element (any previous
6869  // face element had to be added on previous iterations)
6870  for (unsigned iiface = iface; iiface < nele; iiface++)
6871  {
6872  // Re-start flag
6873  face_element_added = false;
6874 
6875  // Get the candidate element
6876  ele_face_pt = face_el_pt[iiface];
6877 
6878  // Check that the candidate element has not been done
6879  if (!(done_el[ele_face_pt]))
6880  {
6881  // Get the left and right nodes of the current element
6882  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6883  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6884 
6885  // New element fits at the left of segment and is not inverted
6886  if (left_node_pt == local_right_node_pt)
6887  {
6888  left_node_pt = local_left_node_pt;
6889  sorted_el_pt.push_front(ele_face_pt);
6890  is_inverted[ele_face_pt] = false;
6891  face_element_added = true;
6892  }
6893  // New element fits at the left of segment and is inverted
6894  else if (left_node_pt == local_left_node_pt)
6895  {
6896  left_node_pt = local_right_node_pt;
6897  sorted_el_pt.push_front(ele_face_pt);
6898  is_inverted[ele_face_pt] = true;
6899  face_element_added = true;
6900  }
6901  // New element fits on the right of segment and is not inverted
6902  else if (right_node_pt == local_left_node_pt)
6903  {
6904  right_node_pt = local_right_node_pt;
6905  sorted_el_pt.push_back(ele_face_pt);
6906  is_inverted[ele_face_pt] = false;
6907  face_element_added = true;
6908  }
6909  // New element fits on the right of segment and is inverted
6910  else if (right_node_pt == local_right_node_pt)
6911  {
6912  right_node_pt = local_left_node_pt;
6913  sorted_el_pt.push_back(ele_face_pt);
6914  is_inverted[ele_face_pt] = true;
6915  face_element_added = true;
6916  }
6917 
6918  if (face_element_added)
6919  {
6920  done_el[ele_face_pt] = true;
6921  nsorted_face_elements++;
6922  break;
6923  }
6924 
6925  } // if (!(done_el[ele_face_pt]))
6926  } // for (iiface<nnon_halo_face_element)
6927  } while (face_element_added &&
6928  (nsorted_face_elements < nnon_halo_face_elements));
6929 
6930  // Store the created segment in the vector of segments
6931  segment_sorted_ele_pt.push_back(sorted_el_pt);
6932 
6933  } // while(nsorted_face_elements < nnon_halo_face_elements);
6934 
6935  // --------------------------------------------------------------
6936  // Third: We have the face elements sorted, now assign boundary
6937  // coordinates to the nodes in the segments and compute the
6938  // arclength of the segment
6939  // --------------------------------------------------------------
6940 
6941  // Vector of sets that stores the nodes of each segment based on a
6942  // lexicographically order starting from the bottom left node of
6943  // each segment
6944  Vector<std::set<Node*>> segment_all_nodes_pt;
6945 
6946  // The number of segments in this processor
6947  const unsigned nsegments = segment_sorted_ele_pt.size();
6948 
6949 #ifdef PARANOID
6950  if (nnon_halo_face_elements > 0 && nsegments == 0)
6951  {
6952  std::ostringstream error_message;
6953  error_message
6954  << "The number of segments is zero, but the number of nonhalo\n"
6955  << "elements is: (" << nnon_halo_face_elements << ")\n";
6956  throw OomphLibError(error_message.str(),
6957  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6958  "values_for_internal_boundary()",
6959  OOMPH_EXCEPTION_LOCATION);
6960  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6961 #endif
6962 
6963  // The arclength of each segment in the current processor
6964  Vector<double> segment_arclength(nsegments);
6965 
6966  // The initial zeta for the segment
6967  Vector<double> initial_zeta_segment(nsegments);
6968 
6969  // The final zeta for the segment
6970  Vector<double> final_zeta_segment(nsegments);
6971 
6972  // Go through all the segments and compute the LOCAL boundary
6973  // coordinates
6974  for (unsigned is = 0; is < nsegments; is++)
6975  {
6976 #ifdef PARANOID
6977  if (segment_sorted_ele_pt[is].size() == 0)
6978  {
6979  std::ostringstream error_message;
6980  error_message << "The (" << is << ")-th segment has no elements\n";
6981  throw OomphLibError(error_message.str(),
6982  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6983  "values_for_internal_boundary()",
6984  OOMPH_EXCEPTION_LOCATION);
6985  } // if (segment_sorted_ele_pt[is].size() == 0)
6986 #endif
6987 
6988  // Get access to the first element on the segment
6989  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6990 
6991  // Number of nodes
6992  const unsigned nnod = first_ele_pt->nnode();
6993 
6994  // Get the first node of the current segment
6995  Node* first_node_pt = first_ele_pt->node_pt(0);
6996  if (is_inverted[first_ele_pt])
6997  {
6998  first_node_pt = first_ele_pt->node_pt(nnod - 1);
6999  }
7000 
7001  // Get access to the last element on the segment
7002  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
7003 
7004  // Get the last node of the current segment
7005  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
7006  if (is_inverted[last_ele_pt])
7007  {
7008  last_node_pt = last_ele_pt->node_pt(0);
7009  }
7010 
7011  // Coordinates of left node
7012  double x_left = first_node_pt->x(0);
7013  double y_left = first_node_pt->x(1);
7014 
7015  // Initialise boundary coordinate (local boundary coordinate for
7016  // boundaries with more than one segment)
7017  Vector<double> zeta(1, 0.0);
7018 
7019  // If we have associated a GeomObject then it is not necessary to
7020  // compute the arclength, only read the values from the nodes at
7021  // the edges
7022  if (this->boundary_geom_object_pt(b) != 0)
7023  {
7024  first_node_pt->get_coordinates_on_boundary(b, zeta);
7025  initial_zeta_segment[is] = zeta[0];
7026  last_node_pt->get_coordinates_on_boundary(b, zeta);
7027  final_zeta_segment[is] = zeta[0];
7028  }
7029 
7030  // Lexicographically bottom left node
7031  std::set<Node*> local_nodes_pt;
7032  local_nodes_pt.insert(first_node_pt);
7033 
7034  // Now loop over nodes in order
7035  for (std::list<FiniteElement*>::iterator it =
7036  segment_sorted_ele_pt[is].begin();
7037  it != segment_sorted_ele_pt[is].end();
7038  it++)
7039  {
7040  // Get element
7041  FiniteElement* el_pt = *it;
7042 
7043  // Start node and increment
7044  unsigned k_nod = 1;
7045  int nod_diff = 1;
7046  if (is_inverted[el_pt])
7047  {
7048  k_nod = nnod - 2;
7049  nod_diff = -1;
7050  }
7051 
7052  // Loop over nodes
7053  for (unsigned j = 1; j < nnod; j++)
7054  {
7055  Node* nod_pt = el_pt->node_pt(k_nod);
7056  k_nod += nod_diff;
7057 
7058  // Coordinates of right node
7059  double x_right = nod_pt->x(0);
7060  double y_right = nod_pt->x(1);
7061 
7062  // Increment boundary coordinate
7063  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
7064  (y_right - y_left) * (y_right - y_left));
7065 
7066  // Increment reference coordinate
7067  x_left = x_right;
7068  y_left = y_right;
7069 
7070  // Get lexicographically bottom left node but only
7071  // use vertex nodes as candidates
7072  local_nodes_pt.insert(nod_pt);
7073 
7074  } // for (j < nnod)
7075  } // iterator over the elements in the segment
7076 
7077  // Store the arclength of the segment
7078  segment_arclength[is] = zeta[0];
7079 
7080  // Add the nodes for the corresponding segment in the container
7081  segment_all_nodes_pt.push_back(local_nodes_pt);
7082 
7083  } // for (is < nsegments)
7084 
7085  // ------------------------------------------------------------------
7086  // Fourth: Now we have the segments sorted, with arclength and with
7087  // LOCAL arclength assigned to the nodes. Procced to re-scale the
7088  // coordinates on the nodes based on the arclength
7089  // ------------------------------------------------------------------
7090 
7091  // ------------------------------------------------------------------
7092  // Clear the original storages
7093  Boundary_segment_inverted[b].clear();
7094  Boundary_segment_initial_coordinate[b].clear();
7095  Boundary_segment_final_coordinate[b].clear();
7096 
7097  Boundary_segment_initial_zeta[b].clear();
7098  Boundary_segment_final_zeta[b].clear();
7099 
7100  Boundary_segment_initial_arclength[b].clear();
7101  Boundary_segment_final_arclength[b].clear();
7102 
7103  // Get the zeta values for the first and last node in the boundary
7104  Vector<double> first_node_zeta_coordinate(1, 0.0);
7105  Vector<double> last_node_zeta_coordinate(1, 0.0);
7106  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
7107  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
7108 
7109  // Get the boundary arclength
7110  const double boundary_arclength =
7111  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
7112 
7113  // Go through the segments and get the first and last node for each
7114  // segment
7115  for (unsigned is = 0; is < nsegments; is++)
7116  {
7117  // Get the first face element of the segment
7118  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
7119 
7120  // The number of nodes
7121  const unsigned nnod = first_face_ele_pt->nnode();
7122 
7123  // ... and the first node of the segment
7124  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7125  if (is_inverted[first_face_ele_pt])
7126  {
7127  first_node_pt = first_face_ele_pt->node_pt(nnod - 1);
7128  }
7129 
7130  // Get the bound coordinates of the node
7131  Vector<double> zeta_first(1);
7132  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7133 
7134  // Get the last face element of the segment
7135  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7136 
7137  // ... and the last node of the segment
7138  Node* last_node_pt = last_face_ele_pt->node_pt(nnod - 1);
7139  if (is_inverted[last_face_ele_pt])
7140  {
7141  last_node_pt = last_face_ele_pt->node_pt(0);
7142  }
7143 
7144  // Get the bound coordinates of the node
7145  Vector<double> zeta_last(1);
7146  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7147 
7148  // Now that we have the first and last node of the segment, get
7149  // the coordinates of the nodes
7150  Vector<double> first_node_coord(2);
7151  Vector<double> last_node_coord(2);
7152  for (unsigned i = 0; i < 2; i++)
7153  {
7154  first_node_coord[i] = first_node_pt->x(i);
7155  last_node_coord[i] = last_node_pt->x(i);
7156  }
7157 
7158  // Re-assign the values to identify the segments on the new mesh
7159  Boundary_segment_inverted[b].push_back(0);
7160  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7161  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7162 
7163  // Check if the boudary has an associated GeomObject
7164  if (this->boundary_geom_object_pt(b) != 0)
7165  {
7166  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7167  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7168  }
7169  else
7170  {
7171  // Re-assign the values and re-scale them
7172  Boundary_segment_initial_arclength[b].push_back(zeta_first[0] *
7173  boundary_arclength);
7174  Boundary_segment_final_arclength[b].push_back(zeta_last[0] *
7175  boundary_arclength);
7176  }
7177 
7178  } // for (is < nsegments)
7179 
7180  // Clean all the created face elements
7181  for (unsigned i = 0; i < nele; i++)
7182  {
7183  delete face_el_pt[i];
7184  face_el_pt[i] = 0;
7185  }
7186  }
7187 
7188 #endif // OOMPH_HAS_MPI
7189 
7190 
7191 #ifdef OOMPH_HAS_TRIANGLE_LIB
7192 
7193  //========================================================================
7194  /// Create TriangulateIO object via the .poly file
7195  //========================================================================
7196  template<class ELEMENT>
7198  const std::string& poly_file_name,
7199  TriangulateIO& triangulate_io,
7200  bool& use_attributes)
7201  {
7202  // Process poly file
7203  // -----------------
7204  std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
7205  if (!poly_file)
7206  {
7207  throw OomphLibError("Error opening .poly file\n",
7208  OOMPH_CURRENT_FUNCTION,
7209  OOMPH_EXCEPTION_LOCATION);
7210  }
7211 
7212  // Initialize triangulateio structure
7213  TriangleHelper::initialise_triangulateio(triangulate_io);
7214 
7215  // Ignore the first line with structure description
7216  poly_file.ignore(80, '\n');
7217 
7218  // Read and store number of nodes
7219  unsigned invertices;
7220  poly_file >> invertices;
7221  triangulate_io.numberofpoints = invertices;
7222 
7223  // Initialisation of the point list
7224  triangulate_io.pointlist =
7225  (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7226 
7227  // Read and store spatial dimension of nodes
7228  unsigned mesh_dim;
7229  poly_file >> mesh_dim;
7230 
7231  if (mesh_dim == 0)
7232  {
7233  mesh_dim = 2;
7234  }
7235 
7236 #ifdef PARANOID
7237  if (mesh_dim != 2)
7238  {
7239  throw OomphLibError("The dimension must be 2\n",
7240  OOMPH_CURRENT_FUNCTION,
7241  OOMPH_EXCEPTION_LOCATION);
7242  }
7243 #endif
7244 
7245  // Read and check the flag for attributes
7246  unsigned nextras;
7247  poly_file >> nextras;
7248 
7249  triangulate_io.numberofpointattributes = 0;
7250  triangulate_io.pointattributelist = (double*)NULL;
7251 
7252  // Read and check the flag for boundary markers
7253  unsigned nodemarkers;
7254  poly_file >> nodemarkers;
7255  triangulate_io.pointmarkerlist = (int*)NULL;
7256 
7257 #ifdef PARANOID
7258  // Reading the .poly with the oomph.lib we need
7259  // to set the point attribute and markers to 0
7260  if (nextras != 0 || nodemarkers != 0)
7261  {
7262  oomph_info << "===================================================="
7263  << std::endl
7264  << std::endl;
7265  oomph_info << "Reading the .poly file via oomph_lib \n"
7266  << "point's attribute and point's markers \n"
7267  << "are automatically set to 0" << std::endl;
7268  oomph_info << "===================================================="
7269  << std::endl;
7270  }
7271 #endif
7272 
7273  // Dummy for node number (and attribute or markers if included)
7274  unsigned dummy_value;
7275  unsigned count_point = 0;
7276  std::string test_string;
7277 
7278  // Skip line with commentary
7279  getline(poly_file, test_string, '#');
7280  poly_file.ignore(80, '\n');
7281 
7282  // Read and store all the nodes coordinates
7283  // (hole's vertices as well)
7284  for (unsigned count = 0; count < invertices; count++)
7285  {
7286  poly_file >> dummy_value;
7287  poly_file >> triangulate_io.pointlist[count_point];
7288  poly_file >> triangulate_io.pointlist[count_point + 1];
7289  if (nextras != 0 || nodemarkers != 0)
7290  {
7291  for (unsigned j = 0; j < nextras; j++)
7292  {
7293  poly_file >> dummy_value;
7294  }
7295  }
7296  else if (nextras != 0 && nodemarkers != 0)
7297  {
7298  for (unsigned j = 0; j < nextras; j++)
7299  {
7300  poly_file >> dummy_value;
7301  poly_file >> dummy_value;
7302  }
7303  }
7304  // Read the next line
7305  poly_file.ignore(80, '\n');
7306 
7307  // Skip line with commentary for internal box whether found
7308  if (poly_file.get() == '#')
7309  {
7310  poly_file.ignore(80, '\n');
7311  }
7312  // If read the char should be put back in the string
7313 
7314  else
7315  {
7316  poly_file.unget();
7317  }
7318  count_point += 2;
7319  }
7320 
7321  // The line with the segment's commentary has been skipped
7322  // by the command of the last loop
7323 
7324  // Read and store the number of segments
7325  unsigned dummy_seg;
7326  unsigned inelements;
7327  poly_file >> inelements;
7328 
7329  unsigned segment_markers;
7330  poly_file >> segment_markers;
7331 
7332  // Marker list should be provided by the user to assign
7333  // each segment to a boundary
7334 #ifdef PARANOID
7335  if (segment_markers != 1)
7336  {
7337  std::ostringstream error_stream;
7338  error_stream << "The segment marker should be provided \n"
7339  << "In order to assign each segment to a boundary \n "
7340  << std::endl;
7341 
7342  throw OomphLibError(
7343  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
7344  }
7345 #endif
7346 
7347  triangulate_io.numberofsegments = inelements;
7348  triangulate_io.segmentlist =
7349  (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7350  triangulate_io.segmentmarkerlist =
7351  (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
7352 
7353  // Read all the segments edges and markers
7354  for (unsigned i = 0; i < 2 * inelements; i += 2)
7355  {
7356  poly_file >> dummy_seg;
7357  poly_file >> triangulate_io.segmentlist[i];
7358  poly_file >> triangulate_io.segmentlist[i + 1];
7359  if (segment_markers != 0)
7360  {
7361  poly_file >> triangulate_io.segmentmarkerlist[i / 2];
7362  }
7363 
7364  // Skip line with commentary
7365  poly_file.ignore(80, '\n');
7366  }
7367 
7368  // Read and store the number of holes if given
7369  // Skip line with commentary
7370  if (getline(poly_file, test_string, '#'))
7371  {
7372  poly_file.ignore(80, '\n');
7373 
7374  unsigned dummy_hole;
7375  unsigned nhole;
7376  poly_file >> nhole;
7377 
7378  triangulate_io.numberofholes = nhole;
7379  triangulate_io.holelist =
7380  (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7381 
7382  // Loop over the holes to get centre coords and store value onto the
7383  // TriangulateIO object
7384  for (unsigned i = 0; i < 2 * nhole; i += 2)
7385  {
7386  poly_file >> dummy_hole;
7387  poly_file >> triangulate_io.holelist[i];
7388  poly_file >> triangulate_io.holelist[i + 1];
7389  }
7390  }
7391 
7392  // Read and store the number of regions if given
7393  // Skip line with commentary
7394  if (getline(poly_file, test_string, '#'))
7395  {
7396  poly_file.ignore(80, '\n');
7397 
7398  unsigned dummy_region;
7399  unsigned nregion;
7400  poly_file >> nregion;
7401  std::cerr << "Regions: " << nregion << std::endl;
7402  getchar();
7403 
7404  triangulate_io.numberofregions = nregion;
7405  triangulate_io.regionlist =
7406  (double*)malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7407 
7408  // Check for using regions
7409  if (nregion > 0)
7410  {
7411  use_attributes = true;
7412  }
7413 
7414  // Loop over the regions to get coords and store value onto the
7415  // TriangulateIO object
7416  for (unsigned i = 0; i < nregion; i++)
7417  {
7418  poly_file >> dummy_region;
7419  poly_file >> triangulate_io.regionlist[4 * i];
7420  poly_file >> triangulate_io.regionlist[4 * i + 1];
7421  poly_file >> triangulate_io.regionlist[4 * i + 2];
7422  triangulate_io.regionlist[4 * i + 3] = 0.0;
7423  }
7424  }
7425  }
7426 
7427 #endif
7428 
7429 #ifdef OOMPH_HAS_TRIANGLE_LIB
7430 #ifdef OOMPH_HAS_MPI
7431 
7432  //======================================================================
7433  /// Used to dump info. related with distributed triangle meshes
7434  //======================================================================
7435  template<class ELEMENT>
7437  std::ostream& dump_file)
7438  {
7439  // First check that the mesh is distributed
7440  if (this->is_mesh_distributed())
7441  {
7442  // Save the original number of boundaries
7443  const unsigned nboundary = this->nboundary();
7444  dump_file << nboundary << " # number of original boundaries" << std::endl;
7445 
7446  // Save the number of shared boundaries
7447  const unsigned nshared_boundaries = this->nshared_boundaries();
7448  dump_file << nshared_boundaries << " # number of shared boundaries"
7449  << std::endl;
7450 
7451  // Save the initial and final shared boundaries ids
7452  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7453  dump_file << init_shd_bnd_id << " # initial shared boundaries id"
7454  << std::endl;
7455 
7456  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7457  dump_file << final_shd_bnd_id << " # final shared boundaries id"
7458  << std::endl;
7459 
7460  // Save the number of processors
7461  const unsigned nprocs = this->shared_boundaries_ids().size();
7462  dump_file << nprocs << " # number of processors" << std::endl;
7463 
7464  // Now save the processors ids and the shared boundary created
7465  // by them
7466  for (unsigned ip = 0; ip < nprocs; ip++)
7467  {
7468  for (unsigned jp = 0; jp < nprocs; jp++)
7469  {
7470  if (ip != jp)
7471  {
7472  // Get the number of shared boundaries with it these two
7473  // processors
7474  const unsigned nshared_boundaries_iproc_jproc =
7475  this->shared_boundaries_ids(ip, jp).size();
7476 
7477  // Save the number of shared boundaries with in these two
7478  // processors
7479  dump_file << nshared_boundaries_iproc_jproc
7480  << " # number of shared boundaries with in two "
7481  << "processors" << std::endl;
7482  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7483  {
7484  const unsigned shared_boundary_id =
7485  this->shared_boundaries_ids(ip, jp, is);
7486  dump_file << ip << " " << jp << " " << shared_boundary_id
7487  << " # ip jp shared_boundary of processors ip and jp"
7488  << std::endl;
7489 
7490  } // for (is < nshared_boundaries_iproc_jproc)
7491  }
7492  } // for (jp < nprocs)
7493  } // for (ip < nprocs)
7494 
7495  // Now save the info. that states which shared boundary overlaps
7496  // an internal boundary
7497 
7498  // First check if there are shared boundaries overlapping internal
7499  // boundaries
7500  const unsigned nshared_boundaries_overlap_internal_boundaries =
7501  this->nshared_boundary_overlaps_internal_boundary();
7502  dump_file << nshared_boundaries_overlap_internal_boundaries
7503  << " # number of shared boundaries that overlap internal "
7504  << "boundaries" << std::endl;
7505 
7506  if (nshared_boundaries_overlap_internal_boundaries > 0)
7507  {
7508  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7509  {
7510  // Check if the current shared boundary overlaps an internal
7511  // boundary
7512  if (this->shared_boundary_overlaps_internal_boundary(isb))
7513  {
7514  // Which internal boundary is overlapped by the shared
7515  // boundary
7516  const unsigned overlapped_internal_boundary =
7517  shared_boundary_overlapping_internal_boundary(isb);
7518  // Save the shared boundary that overlaps the internal boundary
7519  dump_file << isb << " " << overlapped_internal_boundary
7520  << " # the shared boundary overlaps the internal "
7521  << "boundary " << std::endl;
7522 
7523  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7524  } // for (isb < final_shd_bnd_id)
7525  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7526 
7527  // Now save the info. related with the initial and final
7528  // boundary coordinates for each original boundary
7529 
7530  // Go through all the (original) boundaries to update the initial
7531  // and final boundary coordinates
7532  for (unsigned b = 0; b < nboundary; b++)
7533  {
7534  // Check if the boundary zeta coordinates for this boundary have
7535  // been already assigned, if that is the case then state the
7536  // flag to know that info. should be read
7537  if (Assigned_segments_initial_zeta_values[b])
7538  {
7539  // The boundary coordinates have been computed then state
7540  // the flag and save the info.
7541  dump_file << "1 # assigned boundary coordinates initial zeta values"
7542  << std::endl;
7543 
7544  // Save the initial and final boundary coordinates, same as
7545  // the initial and final zeta values for each boundary
7546 
7547  // First the vertices coordinates
7548  Vector<double> initial_coordinates =
7549  this->boundary_initial_coordinate(b);
7550 
7551  Vector<double> final_coordinates = this->boundary_final_coordinate(b);
7552 
7553  dump_file << std::setprecision(14) << initial_coordinates[0] << " "
7554  << initial_coordinates[1]
7555  << " # initial coordinates for the current boundary"
7556  << std::endl;
7557 
7558  dump_file << std::setprecision(14) << final_coordinates[0] << " "
7559  << final_coordinates[1]
7560  << " # final coordinates for the current boundary"
7561  << std::endl;
7562 
7563  // ... then the zeta values
7564 
7565 #ifdef PARANOID
7566  // Get the number of zeta coordinates (should be one)
7567  const unsigned zeta_size =
7568  this->boundary_initial_zeta_coordinate(b).size();
7569 
7570  if (zeta_size != 1)
7571  {
7572  std::ostringstream error_message;
7573  error_message
7574  << "The dimension for the zeta values container is different\n"
7575  << "from 1, the current implementation only supports\n"
7576  << "one-dimensioned zeta containers\n\n";
7577  throw OomphLibError(
7578  error_message.str(),
7579  "TriangleMesh::dump_distributed_info_for_restart()",
7580  OOMPH_EXCEPTION_LOCATION);
7581  }
7582 #endif
7583 
7584  Vector<double> zeta_initial =
7585  this->boundary_initial_zeta_coordinate(b);
7586  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7587 
7588  dump_file << std::setprecision(14) << zeta_initial[0]
7589  << " # initial zeta value for the current boundary"
7590  << std::endl;
7591 
7592  dump_file << std::setprecision(14) << zeta_final[0]
7593  << " # final zeta value for the current boundary"
7594  << std::endl;
7595 
7596  // Get the number of segments of the current boundary
7597  const unsigned nsegments = this->nboundary_segment(b);
7598  // Save the number of segments of the current boundary
7599  dump_file << b << " " << nsegments
7600  << " # of segments for the current boundary" << std::endl;
7601 
7602  // ... and then save that info for each segments
7603  for (unsigned is = 0; is < nsegments; is++)
7604  {
7605  // First the vertices coordinates
7606  Vector<double> initial_segment_coordinates =
7607  this->boundary_segment_initial_coordinate(b)[is];
7608  Vector<double> final_segment_coordinates =
7609  this->boundary_segment_final_coordinate(b)[is];
7610 
7611  dump_file
7612  << std::setprecision(14) << initial_segment_coordinates[0] << " "
7613  << initial_segment_coordinates[1]
7614  << " # initial segment coordinates for the current boundary"
7615  << std::endl;
7616 
7617  dump_file << std::setprecision(14) << final_segment_coordinates[0]
7618  << " " << final_segment_coordinates[1]
7619  << " # final segment coordinates for the current boundary"
7620  << std::endl;
7621 
7622  // ... then the zeta values
7623 
7624  if (this->boundary_geom_object_pt(b) != 0)
7625  {
7626  const double zeta_segment_initial =
7627  this->boundary_segment_initial_zeta(b)[is];
7628  const double zeta_segment_final =
7629  this->boundary_segment_final_zeta(b)[is];
7630 
7631  dump_file
7632  << std::setprecision(14) << zeta_segment_initial
7633  << " # initial segment zeta value for the current boundary"
7634  << std::endl;
7635 
7636  dump_file
7637  << std::setprecision(14) << zeta_segment_final
7638  << " # final segment zeta value for the current boundary"
7639  << std::endl;
7640  }
7641  else
7642  {
7643  const double arclength_segment_initial =
7644  this->boundary_segment_initial_arclength(b)[is];
7645  const double arclength_segment_final =
7646  this->boundary_segment_final_arclength(b)[is];
7647 
7648  dump_file
7649  << std::setprecision(14) << arclength_segment_initial
7650  << " # initial segment arclength for the current boundary"
7651  << std::endl;
7652 
7653  dump_file << std::setprecision(14) << arclength_segment_final
7654  << " # final segment arclength for the current boundary"
7655  << std::endl;
7656 
7657  } // else if (this->boundary_geom_object_pt(b)!=0)
7658 
7659  } // for (is < nsegments)
7660 
7661  } // if (Assigned_segments_initial_zeta_values[b])
7662  else
7663  {
7664  // The boundary coordinates have NOT been computed then state
7665  // the flag and save the info.
7666  dump_file << "0 # assigned boundary coordinates initial zeta values"
7667  << std::endl;
7668  }
7669 
7670  } // for (b < nboundary)
7671 
7672  } // if (this->is_mesh_distributed())
7673  }
7674 
7675  //======================================================================
7676  /// Used to read info. related with distributed triangle meshes
7677  //======================================================================
7678  template<class ELEMENT>
7680  std::istream& restart_file)
7681  {
7682  // First check that the mesh is distributed
7683  if (this->is_mesh_distributed())
7684  {
7685  // Read the number of original boundaries
7686  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7687 
7688 #ifdef PARANOID
7689  if (n_boundary != this->nboundary())
7690  {
7691  std::ostringstream error_message;
7692  error_message
7693  << "The number of boundaries (" << n_boundary << ") on the "
7694  << "file used for restarting is different\nfrom the number of "
7695  << "boundaries (" << this->nboundary() << ") on the current "
7696  << "mesh!!!\n\n\n";
7697  throw OomphLibError(error_message.str(),
7698  "TriangleMesh::read_distributed_info_for_restart()",
7699  OOMPH_EXCEPTION_LOCATION);
7700  }
7701 #endif
7702 
7703  // Read the number of shared boundaries
7704  unsigned n_shared_boundaries = read_unsigned_line_helper(restart_file);
7705  // We need to read the data because it comes in the file (add and
7706  // substract to avoid compilation warning)
7707  n_shared_boundaries++;
7708  n_shared_boundaries--;
7709 
7710  // Read the initial and final shared boundaries ids
7711  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7712  // We need to read the data because it comes in the file (add and
7713  // substract to avoid compilation warning)
7714  init_shd_bnd_id++;
7715  init_shd_bnd_id--;
7716  // Add and substract to avoid compilation warning
7717  unsigned final_shd_bnd_id = read_unsigned_line_helper(restart_file);
7718  // We need to read the data because it comes in the file (add and
7719  // substract to avoid compilation warning)
7720  final_shd_bnd_id++;
7721  final_shd_bnd_id--;
7722 
7723  // Read the number of processors involved in the generation of
7724  // mesh before restart
7725  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7726 
7727 #ifdef PARANOID
7728  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7729  {
7730  std::ostringstream error_message;
7731  error_message
7732  << "The number of previously used processors (" << n_procs
7733  << ") (read from the restart file) is different\nfrom the "
7734  << "number of current used processors ("
7735  << this->communicator_pt()->nproc() << ")\n\n";
7736  throw OomphLibError(error_message.str(),
7737  "TriangleMesh::read_distributed_info_for_restart()",
7738  OOMPH_EXCEPTION_LOCATION);
7739  }
7740 #endif
7741 
7742  // Clear all previuos info. related with shared boundaries
7743  this->shared_boundaries_ids().clear();
7744  this->shared_boundary_from_processors().clear();
7745  this->shared_boundary_overlaps_internal_boundary().clear();
7746 
7747  // Create the storage for the shared boundaries ids related with
7748  // the processors
7749  this->shared_boundaries_ids().resize(n_procs);
7750 
7751  // Now read the processors ids and the shared boundary created
7752  // by them
7753  for (unsigned ip = 0; ip < n_procs; ip++)
7754  {
7755  // Create the storage for the shared boundaries ids related with
7756  // the processors
7757  this->shared_boundaries_ids(ip).resize(n_procs);
7758  for (unsigned jp = 0; jp < n_procs; jp++)
7759  {
7760  if (ip != jp)
7761  {
7762  // Read the number of shared boundaries with in these two
7763  // processors
7764  const unsigned nshared_boundaries_iproc_jproc =
7765  read_unsigned_line_helper(restart_file);
7766  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7767  {
7768  // Get the processors
7769  unsigned tmp_ip;
7770  restart_file >> tmp_ip;
7771  unsigned tmp_jp;
7772  restart_file >> tmp_jp;
7773 
7774  // Get the shared boundary id created by these two
7775  // processors
7776  const unsigned shared_boundary_id =
7777  read_unsigned_line_helper(restart_file);
7778 
7779  // Update the info. of the processors that give rise to
7780  // the shared boundaries
7781  this->shared_boundaries_ids(ip, jp).push_back(shared_boundary_id);
7782 
7783  // Update the structure that states the processors that
7784  // gave rise to the shared boundary
7785  Vector<unsigned> processors(2);
7786  processors[0] = ip;
7787  processors[1] = jp;
7788  this->shared_boundary_from_processors()[shared_boundary_id] =
7789  processors;
7790 
7791  } // for (is < nshared_boundaries_iproc_jproc)
7792  }
7793  } // for (jp < n_procs)
7794  } // for (ip < n_procs)
7795 
7796  // Now read the info. that states which shared boundary overlaps
7797  // an internal boundary
7798 
7799  // First check if there are shared boundaries overlapping internal
7800  // boundaries
7801  const unsigned nshared_boundaries_overlap_internal_boundaries =
7802  read_unsigned_line_helper(restart_file);
7803 
7804  for (unsigned isb = 0;
7805  isb < nshared_boundaries_overlap_internal_boundaries;
7806  isb++)
7807  {
7808  // Read the shared boundary that overlaps an internal boundary
7809  unsigned shared_boundary_overlapping;
7810  restart_file >> shared_boundary_overlapping;
7811  // ... and read the internal boundary that overlaps
7812  const unsigned overlapped_internal_boundary =
7813  read_unsigned_line_helper(restart_file);
7814 
7815  // Re-establish the info. of the shared boundaries overlapped
7816  // by internal boundaries
7817  this->shared_boundary_overlaps_internal_boundary()
7818  [shared_boundary_overlapping] = overlapped_internal_boundary;
7819  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7820 
7821  // Now read the info. related with the initial and final
7822  // boundary coordinates for each original boundary
7823 
7824  // Go through all the (original) boundaries to update the initial
7825  // and final boundary coordinates
7826  for (unsigned b = 0; b < n_boundary; b++)
7827  {
7828  // For each boundary check if the boundary coordinates initial
7829  // and final zeta vales were assigned in the restart file
7830  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7831  read_unsigned_line_helper(restart_file);
7832 
7833  if (boundary_coordinates_initial_zeta_values_assigned)
7834  {
7835  // Clear any previous stored info. There should not be
7836  // info. already stored but better clear the info. for the
7837  // boundary
7838  Boundary_initial_coordinate[b].clear();
7839  Boundary_final_coordinate[b].clear();
7840 
7841  Boundary_initial_zeta_coordinate[b].clear();
7842  Boundary_final_zeta_coordinate[b].clear();
7843 
7844  // The info. for the segments
7845  Boundary_segment_inverted[b].clear();
7846  Boundary_segment_initial_coordinate[b].clear();
7847  Boundary_segment_final_coordinate[b].clear();
7848 
7849  Boundary_segment_initial_zeta[b].clear();
7850  Boundary_segment_final_zeta[b].clear();
7851 
7852  Boundary_segment_initial_arclength[b].clear();
7853  Boundary_segment_final_arclength[b].clear();
7854 
7855  // Read the initial and final boundary coordinates, same as
7856  // the initial and final zeta values for each boundary
7857 
7858  // First the vertices coordinates
7859  Vector<double> initial_coordinates(2);
7860 
7861  // Read the initial coordinates
7862  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7863 
7864  // Ignore rest of line
7865  restart_file.ignore(80, '\n');
7866 
7867  Vector<double> final_coordinates(2);
7868 
7869  // Read the final coordinates
7870  restart_file >> final_coordinates[0] >> final_coordinates[1];
7871 
7872  // Ignore rest of line
7873  restart_file.ignore(80, '\n');
7874 
7875  // Set the values in the containers
7876 
7877 
7878  this->boundary_initial_coordinate(b) = initial_coordinates;
7879  this->boundary_final_coordinate(b) = final_coordinates;
7880 
7881  // ... now read the zeta values
7882  Vector<double> zeta_initial(1);
7883  restart_file >> zeta_initial[0];
7884 
7885  // Ignore rest of line
7886  restart_file.ignore(80, '\n');
7887 
7888  Vector<double> zeta_final(1);
7889  restart_file >> zeta_final[0];
7890 
7891  // Ignore rest of line
7892  restart_file.ignore(80, '\n');
7893 
7894  // Set the values in the containers
7895  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7896  this->boundary_final_zeta_coordinate(b) = zeta_final;
7897 
7898  // Get the curent boundary id from the restart file
7899  unsigned current_boundary;
7900  restart_file >> current_boundary;
7901 
7902 #ifdef PARANOID
7903  if (current_boundary != b)
7904  {
7905  std::ostringstream error_message;
7906  error_message
7907  << "The current boundary id from the restart file ("
7908  << current_boundary << ") is different from\nthe boundary id "
7909  << b << "currently used to re-establish the initial and\nfinal "
7910  << "segment's zeta values\n\n";
7911  throw OomphLibError(
7912  error_message.str(),
7913  "TriangleMesh::read_distributed_info_for_restart()",
7914  OOMPH_EXCEPTION_LOCATION);
7915  }
7916 #endif
7917 
7918  // ... and its number of segments
7919  unsigned nsegments;
7920  restart_file >> nsegments;
7921 
7922  // Ignore rest of line
7923  restart_file.ignore(80, '\n');
7924 
7925  // Now read all the segments info.
7926 
7927  // ... and then save that info for each segments
7928  for (unsigned is = 0; is < nsegments; is++)
7929  {
7930  // First the vertices coordinates
7931  Vector<double> initial_segment_coordinates(2);
7932 
7933  // Read the initial coordinates
7934  restart_file >> initial_segment_coordinates[0] >>
7935  initial_segment_coordinates[1];
7936 
7937  // Ignore rest of line
7938  restart_file.ignore(80, '\n');
7939 
7940  Vector<double> final_segment_coordinates(2);
7941 
7942  // Read the final coordinates
7943  restart_file >> final_segment_coordinates[0] >>
7944  final_segment_coordinates[1];
7945 
7946  // Ignore rest of line
7947  restart_file.ignore(80, '\n');
7948 
7949  // Set the values in the containers
7950  this->boundary_segment_initial_coordinate(b).push_back(
7951  initial_segment_coordinates);
7952  this->boundary_segment_final_coordinate(b).push_back(
7953  final_segment_coordinates);
7954 
7955  // ... then the zeta values for the segment
7956  if (this->boundary_geom_object_pt(b) != 0)
7957  {
7958  Vector<double> zeta_segment_initial(1);
7959  restart_file >> zeta_segment_initial[0];
7960 
7961  // Ignore rest of line
7962  restart_file.ignore(80, '\n');
7963 
7964  Vector<double> zeta_segment_final(1);
7965  restart_file >> zeta_segment_final[0];
7966 
7967  // Ignore rest of line
7968  restart_file.ignore(80, '\n');
7969 
7970  // Set the values in the containers for the segment
7971  this->boundary_segment_initial_zeta(b).push_back(
7972  zeta_segment_initial[0]);
7973  this->boundary_segment_final_zeta(b).push_back(
7974  zeta_segment_final[0]);
7975  }
7976  else
7977  {
7978  Vector<double> arclength_segment_initial(1);
7979  restart_file >> arclength_segment_initial[0];
7980 
7981  // Ignore rest of line
7982  restart_file.ignore(80, '\n');
7983 
7984  Vector<double> arclength_segment_final(1);
7985  restart_file >> arclength_segment_final[0];
7986 
7987  // Ignore rest of line
7988  restart_file.ignore(80, '\n');
7989 
7990  // Set the values in the containers for the segment
7991  this->boundary_segment_initial_arclength(b).push_back(
7992  arclength_segment_initial[0]);
7993  this->boundary_segment_final_arclength(b).push_back(
7994  arclength_segment_final[0]);
7995  } // else if (this->boundary_geom_object_pt(b)!=0)
7996 
7997  } // for (is < nsegments)
7998 
7999  } // if (boundary_coordinates_initial_zeta_values_assigned)
8000 
8001  } // for (b < n_boundary)
8002 
8003  } // if (this->is_mesh_distributed())
8004  }
8005 
8006 #endif // #ifdef OOMPH_HAS_MPI
8007 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
8008 
8009  //===================================================================
8010  // Output the nodes on the boundaries and their / respective boundary
8011  // coordinates(into separate tecplot / zones)
8012  //===================================================================
8013  template<class ELEMENT>
8015  std::ostream& outfile)
8016  {
8017  // First get all the elements adjacent to the given boundary, then
8018  // the face elements and extract the nodes on the boundaries using
8019  // the face elements. We can not use the data structure
8020  // Boundary_node_pt since the multi_domain functions add nodes there
8021  // without assigning the required boundary coordinate
8022 
8023  // Store the nodes in a set so we do not have repeated nodes
8024  std::set<Node*> boundary_nodes_pt;
8025  const unsigned n_boundary_ele = this->nboundary_element(b);
8026  for (unsigned e = 0; e < n_boundary_ele; e++)
8027  {
8028  // Get the boundary bulk element
8029  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
8030 #ifdef OOMPH_HAS_MPI
8031  // Only work with nonhalo elements if the mesh is distributed
8032  if (!bulk_ele_pt->is_halo())
8033  {
8034 #endif
8035  // Get the face index
8036  int face_index = this->face_index_at_boundary(b, e);
8037  // Create the face element
8038  FiniteElement* face_ele_pt =
8039  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
8040 
8041  // Get the number of nodes on the face element
8042  const unsigned n_nodes = face_ele_pt->nnode();
8043  for (unsigned i = 0; i < n_nodes; i++)
8044  {
8045  // Get the nodes in the face elements
8046  Node* tmp_node_pt = face_ele_pt->node_pt(i);
8047  // Add the nodes to the set of boundary nodes
8048  boundary_nodes_pt.insert(tmp_node_pt);
8049  } // for (i < n_nodes)
8050 
8051  // Free the memory allocated for the face element
8052  delete face_ele_pt;
8053  face_ele_pt = 0;
8054 #ifdef OOMPH_HAS_MPI
8055  } // if (!bulk_ele_pt->is_halo())
8056 #endif
8057 
8058  } // for (e < n_boundary_ele)
8059 
8060  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
8061  // Set to store the boundary nodes in order
8062  std::set<Vector<double>> set_node_coord;
8063  // Loop over the nodes on the boundary and store them in the set
8064  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
8065  it != boundary_nodes_pt.end();
8066  it++)
8067  {
8068  Node* inode_pt = (*it);
8069 
8070  // Get the node coordinates
8071  const unsigned n_dim = inode_pt->ndim();
8072  Vector<double> node_coord(n_dim + 1);
8073 
8074  // Get the boundary coordinate
8075  Vector<double> zeta(1);
8076  inode_pt->get_coordinates_on_boundary(b, zeta);
8077  node_coord[0] = zeta[0];
8078  for (unsigned j = 0; j < n_dim; j++)
8079  {
8080  node_coord[j + 1] = inode_pt->x(j);
8081  }
8082  set_node_coord.insert(node_coord);
8083  }
8084 
8085  for (std::set<Vector<double>>::iterator it = set_node_coord.begin();
8086  it != set_node_coord.end();
8087  it++)
8088  {
8089  // Get the node coordinates
8090  Vector<double> node_coord = (*it);
8091 
8092  // Output the node coordinates
8093  const unsigned n_dim = node_coord.size() - 1;
8094  for (unsigned j = 0; j < n_dim; j++)
8095  {
8096  outfile << node_coord[j + 1] << " ";
8097  }
8098  // ... add an extra coordinate to avoid error with tecplot
8099  outfile << "0.0" << std::endl;
8100  }
8101 
8102  // ... loop again to plot the bound coordinates
8103  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
8104  for (std::set<Vector<double>>::iterator it = set_node_coord.begin();
8105  it != set_node_coord.end();
8106  it++)
8107  {
8108  // Get the node coordinates
8109  Vector<double> node_coord = (*it);
8110 
8111  // Output the node coordinates
8112  const unsigned n_dim = node_coord.size() - 1;
8113  for (unsigned j = 0; j < n_dim; j++)
8114  {
8115  outfile << node_coord[j + 1] << " ";
8116  }
8117 
8118  // Output the boundary coordinate
8119  outfile << node_coord[0] << std::endl;
8120  }
8121  }
8122 
8123 #ifdef OOMPH_HAS_MPI
8124  //====================================================================
8125  // \short Creates the distributed domain representation. Joins the
8126  // original boundaires, shared boundaries and creates connections among
8127  // them to create the new polygons that represent the distributed
8128  // domain
8129  //====================================================================
8130  template<class ELEMENT>
8132  Vector<TriangleMeshPolygon*>& polygons_pt,
8133  Vector<TriangleMeshOpenCurve*>& open_curves_pt)
8134  {
8135  // Get the outer polygons, internal polygons, internal open curves
8136  // and join them with the shared polylines to create the distributed
8137  // domain representation (the new outer, internal polygons, and new
8138  // internal open curves)
8139 
8140  // Get the rank of the current processor
8141  const unsigned my_rank = this->communicator_pt()->my_rank();
8142 
8143  // *********************************************************************
8144  // Step (2) Get the outer, internal and shared boundaries to create the
8145  // new polygons
8146  // *********************************************************************
8147 
8148  // *********************************************************************
8149  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8150  // a new representation (for example when the boundary was splitted in
8151  // the distribution process)
8152  // *********************************************************************
8153 
8154  // Storage for new created polylines, non sorted
8155  Vector<TriangleMeshPolyLine*> unsorted_outer_polyline_pt;
8156 
8157  // Storing for the polylines on the boundaries
8158  // The first index is for a set of connected polylines
8159  // The second index is for a polyline on a set of connected polylines
8160  Vector<Vector<TriangleMeshPolyLine*>> sorted_outer_curves_pt;
8161 
8162  // Copy the outer boundaries to the vector of polylines
8163  const unsigned nouter = this->Outer_boundary_pt.size();
8164  for (unsigned i = 0; i < nouter; i++)
8165  {
8166  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8167  for (unsigned p = 0; p < npolylines; p++)
8168  {
8169  // Pointer to the current polyline
8170  TriangleMeshPolyLine* tmp_polyline_pt =
8171  this->Outer_boundary_pt[i]->polyline_pt(p);
8172  const unsigned nvertex = tmp_polyline_pt->nvertex();
8173  if (nvertex > 0)
8174  {
8175  // Get the boundary id of the polyline and check if that boundary
8176  // needs a new representation (for example when the boundary was
8177  // splitted in the distribution process)
8178  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8179  if (!boundary_was_splitted(bound_id))
8180  {
8181  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8182  } // if (!boundary_was_splitted(bound_id))
8183  else
8184  {
8185  // Get the polylines that will represent this boundary
8186  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8187  boundary_subpolylines(bound_id);
8188  const unsigned nsub_poly = tmp_vector_polylines.size();
8189 #ifdef PARANOID
8190  if (nsub_poly <= 1)
8191  {
8192  std::ostringstream error_message;
8193  error_message << "The boundary (" << bound_id
8194  << ") was marked to be splitted but\n"
8195  << "there are only (" << nsub_poly
8196  << ") polylines to represent it.\n";
8197  throw OomphLibError(error_message.str(),
8198  OOMPH_CURRENT_FUNCTION,
8199  OOMPH_EXCEPTION_LOCATION);
8200  }
8201 #endif
8202  // Add the new representation of the polylines (sub-polylines)
8203  // to represent this boundary
8204  for (unsigned isub = 0; isub < nsub_poly; isub++)
8205  {
8206  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8207 #ifdef PARANOID
8208  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8209  if (nsvertex == 0)
8210  {
8211  std::ostringstream error_message;
8212  error_message
8213  << "The current chunk (" << isub << ") of the polyline with\n"
8214  << "boundary id (" << bound_id << ") has no vertices\n";
8215  throw OomphLibError(error_message.str(),
8216  OOMPH_CURRENT_FUNCTION,
8217  OOMPH_EXCEPTION_LOCATION);
8218  } // if (nsvertex == 0)
8219 #endif // #ifdef PARANOID
8220  } // for (isub < nsub_poly)
8221  } // else if (!boundary_was_splitted(bound_id))
8222  } // if (nvertex > 0)
8223  } // for (p < npolylines)
8224  } // for (i < nouter)
8225 
8226  // Get the number of unsorted polylines
8227  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8228  if (nunsorted_outer_polyline > 0)
8229  {
8230  // Now that we have all the new unsorted polylines it is time to sort them
8231  // so they be all contiguous
8232  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8233 
8234  } // if (nunsorted_outer_polyline > 0)
8235 
8236  // *********************************************************************
8237  // Step (2.2) Get the internal closed boundaries and check if it is
8238  // necessary to use a new representation (for example when the boundary
8239  // was splitted in the distribution process)
8240  // *********************************************************************
8241 
8242  // Storage for new created polylines, non sorted
8243  Vector<TriangleMeshPolyLine*> unsorted_internal_closed_polyline_pt;
8244 
8245  // Storing for the polylines on the boundaries
8246  // The first index is for a set of connected polylines
8247  // The second index is for a polyline on a set of connected polylines
8248  Vector<Vector<TriangleMeshPolyLine*>> sorted_internal_closed_curves_pt;
8249 
8250  // Copy the internal closed boundaries to the vector of polylines
8251  const unsigned ninternal_closed = this->Internal_polygon_pt.size();
8252  for (unsigned i = 0; i < ninternal_closed; i++)
8253  {
8254  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8255  for (unsigned p = 0; p < npolylines; p++)
8256  {
8257  // Pointer to the current polyline
8258  TriangleMeshPolyLine* tmp_polyline_pt =
8259  this->Internal_polygon_pt[i]->polyline_pt(p);
8260  const unsigned nvertex = tmp_polyline_pt->nvertex();
8261  if (nvertex > 0)
8262  {
8263  // Get the boundary id of the polyline and check if that boundary
8264  // needs a new representation (for example when the boundary was
8265  // splitted in the distribution process)
8266  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8267  if (!boundary_was_splitted(bound_id))
8268  {
8269  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8270  } // if (!boundary_was_splitted(bound_id))
8271  else
8272  {
8273  // Get the polylines that will represent this boundary
8274  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8275  boundary_subpolylines(bound_id);
8276  const unsigned nsub_poly = tmp_vector_polylines.size();
8277 #ifdef PARANOID
8278  if (nsub_poly <= 1)
8279  {
8280  std::ostringstream error_message;
8281  error_message << "The boundary (" << bound_id
8282  << ") was marked to be splitted but\n"
8283  << "there are only (" << nsub_poly
8284  << ") polylines to represent it.\n";
8285  throw OomphLibError(error_message.str(),
8286  OOMPH_CURRENT_FUNCTION,
8287  OOMPH_EXCEPTION_LOCATION);
8288  }
8289 #endif
8290  // Add the new representation of the polylines (sub-polylines)
8291  // to represent this boundary
8292  for (unsigned isub = 0; isub < nsub_poly; isub++)
8293  {
8294  unsorted_internal_closed_polyline_pt.push_back(
8295  tmp_vector_polylines[isub]);
8296 #ifdef PARANOID
8297  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8298  if (nsvertex == 0)
8299  {
8300  std::ostringstream error_message;
8301  error_message
8302  << "The current chunk (" << isub << ") of the polyline with\n"
8303  << "boundary id (" << bound_id << ") has no vertices\n";
8304  throw OomphLibError(error_message.str(),
8305  OOMPH_CURRENT_FUNCTION,
8306  OOMPH_EXCEPTION_LOCATION);
8307  } // if (nsvertex == 0)
8308 #endif // #ifdef PARANOID
8309  } // for (isub < nsub_poly)
8310  } // else if (!boundary_was_splitted(bound_id))
8311  } // if (nvertex > 0)
8312  } // for (p < npolylines)
8313  } // for (i < ninternal_closed)
8314 
8315  const unsigned nunsorted_internal_closed_polyline =
8316  unsorted_internal_closed_polyline_pt.size();
8317 
8318  if (nunsorted_internal_closed_polyline > 0)
8319  {
8320  // Now that we have all the new unsorted polylines it is time to sort them
8321  // so they be all contiguous
8322  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8323  sorted_internal_closed_curves_pt);
8324  }
8325 
8326  // *********************************************************************
8327  // Step (2.3) Get the internal open boundaries and check if it is
8328  // necessary to use a new representation (for example when the boundary
8329  // was splitted in the distribution process)
8330  // *********************************************************************
8331 
8332  // Storage for new created polylines, non sorted
8333  Vector<TriangleMeshPolyLine*> unsorted_internal_open_polyline_pt;
8334 
8335  // Storing for the polylines on the boundaries
8336  // The first index is for a set of connected polylines
8337  // The second index is for a polyline on a set of connected polylines
8338  Vector<Vector<TriangleMeshPolyLine*>> sorted_internal_open_curves_pt;
8339 
8340  // Copy the internal open boundaries to the vector of polylines
8341  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8342  for (unsigned i = 0; i < ninternal_open; i++)
8343  {
8344  const unsigned ncurve_section =
8345  this->Internal_open_curve_pt[i]->ncurve_section();
8346  for (unsigned p = 0; p < ncurve_section; p++)
8347  {
8348  // Pointer to the current polyline
8349  TriangleMeshPolyLine* tmp_polyline_pt =
8350  this->Internal_open_curve_pt[i]->polyline_pt(p);
8351  const unsigned nvertex = tmp_polyline_pt->nvertex();
8352  if (nvertex > 0)
8353  {
8354  // Get the boundary id of the polyline and check if that boundary
8355  // needs a new representation (for example when the boundary was
8356  // splitted in the distribution process)
8357  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8358  if (!boundary_was_splitted(bound_id))
8359  {
8360  // Only include as internal boundaries those not marked as
8361  // shared boundaries
8362  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8363  {
8364  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8365  }
8366  } // if (!boundary_was_splitted(bound_id))
8367  else
8368  {
8369  // Get the polylines that will represent this boundary
8370  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8371  boundary_subpolylines(bound_id);
8372  const unsigned nsub_poly = tmp_vector_polylines.size();
8373 #ifdef PARANOID
8374  if (nsub_poly <= 1)
8375  {
8376  std::ostringstream error_message;
8377  error_message << "The boundary (" << bound_id
8378  << ") was marked to be splitted but\n"
8379  << "there are only (" << nsub_poly
8380  << ") polylines to represent it.\n";
8381  throw OomphLibError(error_message.str(),
8382  OOMPH_CURRENT_FUNCTION,
8383  OOMPH_EXCEPTION_LOCATION);
8384  }
8385 #endif
8386  // Add the new representation of the polylines (sub-polylines)
8387  // to represent this boundary
8388  for (unsigned isub = 0; isub < nsub_poly; isub++)
8389  {
8390  // Only include as internal boundaries those not marked as
8391  // shared boundaries
8392  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8393  {
8394  unsorted_internal_open_polyline_pt.push_back(
8395  tmp_vector_polylines[isub]);
8396  }
8397 #ifdef PARANOID
8398  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8399  if (nsvertex == 0)
8400  {
8401  std::ostringstream error_message;
8402  error_message
8403  << "The current chunk (" << isub << ") of the polyline with\n"
8404  << "boundary id (" << bound_id << ") has no vertices\n";
8405  throw OomphLibError(error_message.str(),
8406  OOMPH_CURRENT_FUNCTION,
8407  OOMPH_EXCEPTION_LOCATION);
8408  } // if (nsvertex == 0)
8409 #endif // #ifdef PARANOID
8410  } // for (isub < nsub_poly)
8411  } // else if (!boundary_was_splitted(bound_id))
8412  } // if (nvertex > 0)
8413  } // for (p < npolylines)
8414  } // for (i < ninternal_open)
8415 
8416  const unsigned nunsorted_internal_open_polyline =
8417  unsorted_internal_open_polyline_pt.size();
8418 
8419  if (nunsorted_internal_open_polyline > 0)
8420  {
8421  // Now that we have all the new unsorted polylines it is time to sort them
8422  // so they be all contiguous
8423  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8424  sorted_internal_open_curves_pt);
8425  }
8426 
8427  // ********************************************************************
8428  // Step (2.4) Sort the polylines on the shared boundaries
8429  // ********************************************************************
8430 
8431  // Storage for new created polylines, non sorted
8432  Vector<TriangleMeshPolyLine*> unsorted_shared_polyline_pt;
8433 
8434  // Special storage for the shared polylines that will be also used
8435  // to connect with the internal boundaries
8436  Vector<TriangleMeshPolyLine*> unsorted_shared_to_internal_polyline_pt;
8437 
8438  // Storing for the polylines on the shared boundaries
8439  // The first index is for a set of connected polylines
8440  // The second index is for a polyline on a set of connected polylines
8441  Vector<Vector<TriangleMeshPolyLine*>> sorted_shared_curves_pt;
8442 
8443  // Copy the shared boudaries to the vector of polylines
8444  const unsigned ncurves = nshared_boundary_curves(my_rank);
8445  for (unsigned i = 0; i < ncurves; i++)
8446  {
8447  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8448  for (unsigned p = 0; p < npolylines; p++)
8449  {
8450  const unsigned nvertex =
8451  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8452  if (nvertex > 0)
8453  {
8454  TriangleMeshPolyLine* tmp_shared_poly_pt =
8455  shared_boundary_polyline_pt(my_rank, i, p);
8456 
8457  // First check if there are shared boundaries overlapping
8458  // internal boundaries
8459  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8460  {
8461  // Get the boundary id of the shared polyline
8462  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8463  // If the shared polyline is marked as internal boundary
8464  // then include it in the special storage to look for
8465  // connection with internal boundaries
8466  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8467  {
8468  unsorted_shared_to_internal_polyline_pt.push_back(
8469  tmp_shared_poly_pt);
8470  }
8471  }
8472  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8473  }
8474  }
8475  }
8476 
8477  // Get the total number of shared polylines
8478  const unsigned nunsorted_shared_polyline =
8479  unsorted_shared_polyline_pt.size();
8480 
8481  if (nunsorted_shared_polyline > 0)
8482  {
8483  // Now that we have all the new unsorted polylines it is time to
8484  // sort them so they be all contiguous
8485  sort_polylines_helper(unsorted_shared_polyline_pt,
8486  sorted_shared_curves_pt);
8487  }
8488 
8489  // ********************************************************************
8490  // Step (3) Join the boundaries (shared, internal and outer to
8491  // create the new polygons)
8492  // ********************************************************************
8493 
8494  // Create the set of curves that will be used to create the new polygons
8495  // Get the total number of curves
8496  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8497  const unsigned ninternal_closed_curves =
8498  sorted_internal_closed_curves_pt.size();
8499  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8500  const unsigned ntotal_curves =
8501  nouter_curves + ninternal_closed_curves + nshared_curves;
8502 
8503  // Add all the polylines to a container
8504  unsigned counter = 0;
8505  Vector<Vector<TriangleMeshPolyLine*>> all_curves_pt(ntotal_curves);
8506 
8507  // Add the shared curves first, this ensure the generation of
8508  // internal polygons defined by the shared boundaries
8509  for (unsigned i = 0; i < nshared_curves; i++, counter++)
8510  {
8511  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8512  }
8513 
8514  // Add the internal polygons (if any)
8515  for (unsigned i = 0; i < ninternal_closed_curves; i++, counter++)
8516  {
8517  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8518  }
8519 
8520  // Add the outer polygons
8521  for (unsigned i = 0; i < nouter_curves; i++, counter++)
8522  {
8523  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8524  }
8525 
8526  // Create the temporary version of the domain by joining the new
8527  // polylines
8528  this->create_tmp_polygons_helper(all_curves_pt, polygons_pt);
8529  // Create the new open curves
8530  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8531  unsorted_shared_to_internal_polyline_pt,
8532  open_curves_pt);
8533 
8534  // ********************************************************************
8535  // Step (4) Create connections among the outer boundaries
8536  // (intersections with themselves)
8537  // ********************************************************************
8538 
8539  // After creating the new boundaries representation (polylines)
8540  // establish the connections of the shared boundaries (with
8541  // themselves or with the original boundaries). This avoids the
8542  // multiple definition of vertices in the domain which cause
8543  // problems when calling Triangle
8544 
8545  this->create_shared_polylines_connections();
8546 
8547  // ------------------------------------------------------------------
8548  // Compute the new holes information. Those from the
8549  // extra_holes_coordinates container, and those from the original
8550  // closed boundaries. Add the holes created by the halo elements
8551  // adjacent to the shared boundaries
8552 
8553  // The storage for the new holes, get those from the
8554  // extra_holes_coordinates container and those from the internal
8555  // closed boundaries that are defined as holes
8556  Vector<Vector<double>> new_holes_coordinates;
8557 
8558  // Copy the holes (those defined by the original internal closed
8559  // boundaries and those in the extra holes container)
8560 
8561  // The holes defined by the original internal closed boundaries
8562  const unsigned n_holes = this->Internal_polygon_pt.size();
8563  for (unsigned h = 0; h < n_holes; h++)
8564  {
8565  Vector<double> hole_coordinates =
8566  this->Internal_polygon_pt[h]->internal_point();
8567  // If the closed boundary is a hole, then copy its hole
8568  if (!hole_coordinates.empty())
8569  {
8570  new_holes_coordinates.push_back(hole_coordinates);
8571  }
8572  } // for (h < n_holes)
8573 
8574  // Is this the first time we are going to copy the extra holes
8575  // coordinates
8576  if (First_time_compute_holes_left_by_halo_elements)
8577  {
8578  // The holes in the extra holes container
8579  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8580  for (unsigned h = 0; h < n_extra_holes; h++)
8581  {
8582  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8583  new_holes_coordinates.push_back(hole_coordinates);
8584  } // for (h < n_extra_holes)
8585 
8586  // Copy the extra holes coordinates
8587  Original_extra_holes_coordinates = Extra_holes_coordinates;
8588 
8589  // Set the flag to false
8590  First_time_compute_holes_left_by_halo_elements = false;
8591 
8592  } // if (First_time_compute_holes_left_by_halo_elements)
8593  else
8594  {
8595  // Not the first time, then only copy the original extra holes
8596  // coordinates
8597  const unsigned n_original_extra_holes =
8598  Original_extra_holes_coordinates.size();
8599  for (unsigned h = 0; h < n_original_extra_holes; h++)
8600  {
8601  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8602  new_holes_coordinates.push_back(hole_coordinates);
8603  } // for (h < n_original_extra_holes)
8604  }
8605 
8606  // Add the holes created by the halo elements adjacent to the shared
8607  // boundaries
8608  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8609 
8610  // Update the holes information, only use the coordinate inside the
8611  // poylgons that define the new domain
8612  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8613 
8614  // tachidok Clear the storage by now
8615  // new_holes_coordinates.clear();
8616 
8617  // Now copy the info. in the extra holes coordinates container
8618  Extra_holes_coordinates = new_holes_coordinates;
8619 
8620  // Do not delete halo(ed) info., this will be "deleted"
8621  // automatically by not passing that information to the new adapted
8622  // mesh. Once the transfer of target areas is performed the halo(ed)
8623  // information is no longer required
8624  }
8625 
8626  //======================================================================
8627  // \short Take the polylines from the shared boundaries and the boundaries
8628  // to create polygons
8629  //======================================================================
8630  template<class ELEMENT>
8632  Vector<Vector<TriangleMeshPolyLine*>>& polylines_pt,
8633  Vector<TriangleMeshPolygon*>& polygons_pt)
8634  {
8635  // Each vector of polylines (curve) is already sorted, it means that
8636  // all the polylines on the vector polylines_pt[i] point to the same
8637  // direction
8638 
8639  // --- Using this fact we should compare the first and last points from
8640  // these arrays of polylines (curves) and compare with the others
8641  // vectors of polylines (curves) end points
8642  // --- Once created a closed curve create a polygon
8643 
8644  // The number of curves
8645  const unsigned ncurves = polylines_pt.size();
8646 
8647  // The number of non sorted curves
8648  const unsigned nunsorted_curves = ncurves;
8649  // The number of sorted curves
8650  unsigned nsorted_curves = 0;
8651 
8652  // Vector to know which ncurve is already done
8653  std::vector<bool> done_curve(ncurves);
8654 
8655  do
8656  {
8657  // The list where to add the curves so that they be contiguous
8658  std::list<Vector<TriangleMeshPolyLine*>> list_building_polygon_pt;
8659 #ifdef PARANOID
8660  // Flag to indicate that a root curve was found
8661  bool root_curve_found = false;
8662 #endif
8663 
8664  // The index for the root_curve (we use it in further iterations as the
8665  // starting index so we dont need to search in already done curves)
8666  unsigned root_curve_idx = 0;
8667 
8668  // Get the root curve
8669  for (unsigned ic = 0; ic < ncurves; ic++)
8670  {
8671  if (!done_curve[ic])
8672  {
8673  root_curve_idx = ic;
8674  nsorted_curves++;
8675 #ifdef PARANOID
8676  root_curve_found = true;
8677 #endif
8678  done_curve[ic] = true;
8679  // ... break the loop
8680  break;
8681  }
8682  }
8683 
8684 #ifdef PARANOID
8685  if (!root_curve_found)
8686  {
8687  std::stringstream err;
8688  err << "The root curve to create a polygon from the shared and "
8689  << "original boundaries was not found!!!\n";
8690  throw OomphLibError(err.str(),
8691  "TriangleMesh::create_tmp_polygons_helper()",
8692  OOMPH_EXCEPTION_LOCATION);
8693  }
8694 #endif
8695 
8696  // Get the root curve
8697  Vector<TriangleMeshPolyLine*> root_curve_pt =
8698  polylines_pt[root_curve_idx];
8699 
8700  // Add the root curve to the list
8701  list_building_polygon_pt.push_back(root_curve_pt);
8702 
8703  // Get the initial and final vertices from the root curve
8704  Vector<double> root_curve_initial_vertex(2);
8705  Vector<double> root_curve_final_vertex(2);
8706 
8707  // We need to get the number of polylines that compose the root curve
8708  const unsigned nroot_curve_polyline = root_curve_pt.size();
8709  // ... and now get the initial and final vertex
8710  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8711  root_curve_pt[nroot_curve_polyline - 1]->final_vertex_coordinate(
8712  root_curve_final_vertex);
8713 
8714  // First check if it already create a polygon
8715  double diff =
8716  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0]) *
8717  (root_curve_initial_vertex[0] - root_curve_final_vertex[0])) +
8718  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1]) *
8719  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8720  diff = sqrt(diff);
8721  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8722  {
8723  // The polyline already create a Polygon, then create it!!!
8724  // Create the curve section representation of the current root curve
8725  Vector<TriangleMeshCurveSection*> curve_section_pt(
8726  nroot_curve_polyline);
8727 
8728  // Copy the polylines into its curve section representation
8729  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8730  {
8731  curve_section_pt[i] = root_curve_pt[i];
8732  }
8733 
8734  // ... and create the Polygon
8735  TriangleMeshPolygon* new_polygon_pt =
8736  new TriangleMeshPolygon(curve_section_pt);
8737 
8738  // Mark the polygon for deletion (in the destructor)
8739  this->Free_polygon_pt.insert(new_polygon_pt);
8740 
8741  // Add the polygon to the output polygons
8742  polygons_pt.push_back(new_polygon_pt);
8743  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8744  // when the curve creates a Polygon by itself
8745  else
8746  {
8747  // Flag to continue iterating while curves be added to the left
8748  // or right of the list of curves
8749  bool added_curve = false;
8750 #ifdef PARANOID
8751  // Flag to know if the "loop" finish because a polygon was
8752  // created or because no more curves can be added to the left or
8753  // right
8754  bool polygon_created = false;
8755 #endif
8756  do
8757  {
8758  added_curve = false;
8759  // If the root curve does not create a closed polygon then add curves
8760  // to the left or right until the curves create a closed polygon
8761  for (unsigned ic = root_curve_idx + 1; ic < ncurves; ic++)
8762  {
8763  if (!done_curve[ic])
8764  {
8765  // Get the current curve
8766  Vector<TriangleMeshPolyLine*> current_curve_pt = polylines_pt[ic];
8767 
8768  // We need to get the number of polylines that compose the
8769  // current curve
8770  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8771 
8772  // ... and get the initial and final coordinates for the current
8773  // curve
8774  Vector<double> current_curve_initial_vertex(2);
8775  Vector<double> current_curve_final_vertex(2);
8776 
8777  current_curve_pt[0]->initial_vertex_coordinate(
8778  current_curve_initial_vertex);
8779  current_curve_pt[ncurrent_curve_polyline - 1]
8780  ->final_vertex_coordinate(current_curve_final_vertex);
8781 
8782  // ---------------------------------------------------------------
8783  // Start adding curves to the left or right
8784  // ---------------------------------------------------------------
8785  diff = ((current_curve_final_vertex[0] -
8786  root_curve_initial_vertex[0]) *
8787  (current_curve_final_vertex[0] -
8788  root_curve_initial_vertex[0])) +
8789  ((current_curve_final_vertex[1] -
8790  root_curve_initial_vertex[1]) *
8791  (current_curve_final_vertex[1] -
8792  root_curve_initial_vertex[1]));
8793  diff = sqrt(diff);
8794  // CURRENT curve to the LEFT of the ROOT curve
8795  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8796  {
8797  // Add the current curve to the left
8798  list_building_polygon_pt.push_front(current_curve_pt);
8799  // Mark the curve as done
8800  done_curve[ic] = true;
8801  // Update the initial vertex values
8802  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8803  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8804  // Increase the number of sorted curves
8805  nsorted_curves++;
8806  // Set the flag to indicate that a curve was added to the list
8807  added_curve = true;
8808  break;
8809  }
8810 
8811  diff = ((current_curve_initial_vertex[0] -
8812  root_curve_initial_vertex[0]) *
8813  (current_curve_initial_vertex[0] -
8814  root_curve_initial_vertex[0])) +
8815  ((current_curve_initial_vertex[1] -
8816  root_curve_initial_vertex[1]) *
8817  (current_curve_initial_vertex[1] -
8818  root_curve_initial_vertex[1]));
8819  diff = sqrt(diff);
8820  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8821  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8822  {
8823  Vector<TriangleMeshPolyLine*> tmp_curve_pt(
8824  ncurrent_curve_polyline);
8825  // Reverse each polyline and back them up
8826  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8827  {
8828  current_curve_pt[it]->reverse();
8829  tmp_curve_pt[it] = current_curve_pt[it];
8830  }
8831  // Now copy them back but in reverse order
8832  unsigned count = 0;
8833  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--, count++)
8834  {
8835  current_curve_pt[count] = tmp_curve_pt[i];
8836  }
8837  // Add the current curve to the left
8838  list_building_polygon_pt.push_front(current_curve_pt);
8839  // Mark the curve as done
8840  done_curve[ic] = true;
8841  // Update the initial vertex values
8842  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8843  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8844  // Increase the number of sorted curves
8845  nsorted_curves++;
8846  // Set the flag to indicate that a curve was added to the list
8847  added_curve = true;
8848  break;
8849  }
8850 
8851  diff = ((current_curve_initial_vertex[0] -
8852  root_curve_final_vertex[0]) *
8853  (current_curve_initial_vertex[0] -
8854  root_curve_final_vertex[0])) +
8855  ((current_curve_initial_vertex[1] -
8856  root_curve_final_vertex[1]) *
8857  (current_curve_initial_vertex[1] -
8858  root_curve_final_vertex[1]));
8859  diff = sqrt(diff);
8860  // CURRENT curve to the RIGHT of the ROOT curve
8861  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8862  {
8863  // Add the current curve to the right
8864  list_building_polygon_pt.push_back(current_curve_pt);
8865  // Mark the curve as done
8866  done_curve[ic] = true;
8867  // Update the initial vertex values
8868  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8869  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8870  // Increase the number of sorted curves
8871  nsorted_curves++;
8872  // Set the flag to indicate that a curve was added to the list
8873  added_curve = true;
8874  break;
8875  }
8876 
8877  diff =
8878  ((current_curve_final_vertex[0] - root_curve_final_vertex[0]) *
8879  (current_curve_final_vertex[0] - root_curve_final_vertex[0])) +
8880  ((current_curve_final_vertex[1] - root_curve_final_vertex[1]) *
8881  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8882  diff = sqrt(diff);
8883  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8884  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8885  {
8886  Vector<TriangleMeshPolyLine*> tmp_curve_pt(
8887  ncurrent_curve_polyline);
8888  // Reverse each polyline and back them up
8889  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8890  {
8891  current_curve_pt[it]->reverse();
8892  tmp_curve_pt[it] = current_curve_pt[it];
8893  }
8894  // Now copy them back but in reverse order
8895  unsigned count = 0;
8896  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--, count++)
8897  {
8898  current_curve_pt[count] = tmp_curve_pt[i];
8899  }
8900  // Add the current curve to the right
8901  list_building_polygon_pt.push_back(current_curve_pt);
8902  // Mark the curve as done
8903  done_curve[ic] = true;
8904  // Update the initial vertex values
8905  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8906  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8907  // Increase the number of sorted curves
8908  nsorted_curves++;
8909  // Set the flag to indicate that a curve was added to the list
8910  added_curve = true;
8911  break;
8912  }
8913 
8914  } // if (!done_curve[ic])
8915 
8916  } // for (ic < ncurves)
8917 
8918  // After adding a curve check if it is possible to create a polygon
8919  double diff =
8920  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0]) *
8921  (root_curve_initial_vertex[0] - root_curve_final_vertex[0])) +
8922  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1]) *
8923  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8924  diff = sqrt(diff);
8925  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8926  {
8927  // If the curves already create a Polygon then go out of the
8928  // loop and create the Polygon
8929  added_curve = false;
8930 #ifdef PARANOID
8931  // Set the flag to indicate that a Polygon has been created
8932  polygon_created = true;
8933 #endif
8934  } // (diff <
8935  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8936  // when the curve creates a Polygon by itself
8937 
8938  } while (added_curve);
8939 
8940 #ifdef PARANOID
8941  if (!polygon_created)
8942  {
8943  std::stringstream error_message;
8944  error_message
8945  << "It was no possible to create a TriangleMeshPolygon with "
8946  << "the input set of curves\n"
8947  << "These are the initial and final vertices in the current "
8948  << "sorted list of\nTriangleMeshPolyLines\n\n";
8949  Vector<double> init_vertex(2);
8950  Vector<double> final_vertex(2);
8951  unsigned icurve = 0;
8952  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8953  list_building_polygon_pt.begin();
8954  it != list_building_polygon_pt.end();
8955  it++, icurve++)
8956  {
8957  const unsigned ncurrent_curve_polyline = (*it).size();
8958  error_message << "TriangleMeshCurve #" << icurve << "\n"
8959  << "-----------------------------------\n";
8960  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8961  {
8962  Vector<double> init_vertex(2);
8963  Vector<double> final_vertex(2);
8964  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8965  (*it)[ip]->final_vertex_coordinate(final_vertex);
8966  error_message << "TriangleMeshPolyLine #" << ip << "\n"
8967  << "Initial vertex: (" << init_vertex[0] << ","
8968  << init_vertex[1] << ")\n"
8969  << "Final vertex: (" << final_vertex[0] << ","
8970  << final_vertex[1] << ")\n";
8971  } // for (ip < ncurrent_curve_polyline)
8972  } // for (it != list_building_polygon_pt.end())
8973 
8974  throw OomphLibError(error_message.str(),
8975  "TriangleMesh::create_tmp_polygons_helper()",
8976  OOMPH_EXCEPTION_LOCATION);
8977 
8978  } // if (!polygon_created)
8979 #endif
8980 
8981  // Create the polygon after joining the curves
8982  unsigned ntotal_polylines = 0;
8983  // Get the total number of polylines
8984  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8985  list_building_polygon_pt.begin();
8986  it != list_building_polygon_pt.end();
8987  it++)
8988  {
8989  ntotal_polylines += (*it).size();
8990  }
8991 
8992  // Create the curve section representation of the curves on the list
8993  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
8994 
8995  // Copy the polylines into its curve section representation
8996  unsigned counter = 0;
8997  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8998  list_building_polygon_pt.begin();
8999  it != list_building_polygon_pt.end();
9000  it++)
9001  {
9002  const unsigned ncurrent_curve_polyline = (*it).size();
9003  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++, counter++)
9004  {
9005  curve_section_pt[counter] = (*it)[ip];
9006  } // for (ip < ncurrent_curve_polyline)
9007  } // Loop over the list of polylines
9008 
9009  // ... and create the Polygon
9010  TriangleMeshPolygon* new_polygon_pt =
9011  new TriangleMeshPolygon(curve_section_pt);
9012 
9013  // Mark the polygon for deletion (in the destructor)
9014  this->Free_polygon_pt.insert(new_polygon_pt);
9015 
9016  // Add the polygon to the output polygons
9017  polygons_pt.push_back(new_polygon_pt);
9018 
9019  } // else
9020  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
9021 
9022  } while (nsorted_curves < nunsorted_curves);
9023  }
9024 
9025  //======================================================================
9026  //\short Take the polylines from the original open curves and created
9027  // new temporaly representations of open curves with the bits of
9028  // original curves not overlapped by shared boundaries
9029  //======================================================================
9030  template<class ELEMENT>
9032  Vector<Vector<TriangleMeshPolyLine*>>& sorted_open_curves_pt,
9033  Vector<TriangleMeshPolyLine*>& unsorted_shared_to_internal_poly_pt,
9034  Vector<TriangleMeshOpenCurve*>& open_curves_pt)
9035  {
9036  // Here search for the connections of the open curves remaining as
9037  // open curves with the shared boundaries markes as internal
9038  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
9039 
9040  // Once identified the connections created with the new internal
9041  // boundaries representations add them to the open curves container
9042  for (unsigned i = 0; i < ninternal_open_curves; i++)
9043  {
9044  // Create the curve section representation of the polylines
9045  const unsigned npoly = sorted_open_curves_pt[i].size();
9046  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
9047  for (unsigned j = 0; j < npoly; j++)
9048  {
9049  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
9050  }
9051  // ... and create the Open Curve
9052  TriangleMeshOpenCurve* new_open_curve_pt =
9053  new TriangleMeshOpenCurve(tmp_curve_section);
9054 
9055  // Mark the open curve for deletion (in the destructor)
9056  this->Free_open_curve_pt.insert(new_open_curve_pt);
9057 
9058  // Add the open curve to the output open curves
9059  open_curves_pt.push_back(new_open_curve_pt);
9060 
9061  } // (i < ninternal_open_curves)
9062  }
9063 
9064  //======================================================================
9065  //\short Check for any possible connections that the array of sorted
9066  // nodes have with original boundary nodes, previous shared polyline
9067  // nodes or with itself polyline nodes. In case that there is a
9068  // connection, get the boundary id to which connects
9069  //======================================================================
9070  template<class ELEMENT>
9072  std::set<FiniteElement*>& element_in_processor_pt,
9073  const int& root_edge_bnd_id,
9074  std::map<std::pair<Node*, Node*>, bool>& overlapped_face,
9075  std::map<unsigned, std::map<Node*, bool>>&
9076  node_on_bnd_not_overlapped_by_shd_bnd,
9077  std::list<Node*>& current_polyline_nodes,
9078  std::map<unsigned, std::list<Node*>>& shared_bnd_id_to_sorted_list_node_pt,
9079  const unsigned& node_degree,
9080  Node*& new_node_pt,
9081  const bool called_from_load_balance)
9082  {
9083  // Initialize the flag to return
9084  int flag_to_return = -1;
9085 
9086  // --------------------------------------------------------------------
9087  // First try to find a connection with any original boundary (keep
9088  // in mind the case when internal boundaries may be overlapped by
9089  // shared boundaries)
9090  // --------------------------------------------------------------------
9091 
9092  // Check if the shared boundary is overlapping an internal boundary
9093  bool overlapping_internal_boundary = false;
9094  // The boundary id overlapped by the current shared boundary
9095  unsigned internal_overlaping_bnd_id = 0;
9096  if (root_edge_bnd_id != -1)
9097  {
9098  // Set the flat to true
9099  overlapping_internal_boundary = true;
9100  // Set the bnd id of the overlapped internal boundary
9101  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
9102  } // if (root_edge_bnd_id != -1)
9103 
9104  // ---------------------------------------------------------------
9105  // Check if the connection is with an original boundary by checking
9106  // if the new node is a boundary node, and it lives in an element
9107  // that is part of the domain
9108  // ---------------------------------------------------------------
9109  if (new_node_pt->is_on_boundary())
9110  {
9111  // Flag to indicate if the node lives in a non overlapped boundary
9112  bool is_node_living_in_non_overlapped_boundary = false;
9113 
9114  // If the node is a boundary node then check in which boundary it
9115  // is
9116  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
9117  for (unsigned bb = 0; bb < noriginal_bnd; bb++)
9118  {
9119  // If the shared boundary overlaps an internal boundary it will
9120  // be indicated by (root_edge_bnd_id != -1), the original
9121  // internal boundary that overlaps is given by the
9122  // root_edge_bnd_id value. We skip that original internal
9123  // boundary because the new node will be obviously ON the
9124  // internal boundary
9125  if (overlapping_internal_boundary)
9126  {
9127  // Is the node on boundary bb?
9128  if (new_node_pt->is_on_boundary(bb))
9129  {
9130  // If overlaping then check that the boundary is different
9131  // from the one that is being overlapped, or if overlapped
9132  // then check that the node is on an edge on the bb
9133  // boundary not overlapped by a shared boundary
9134  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9135  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9136  if (bb != internal_overlaping_bnd_id ||
9137  ((bb == internal_overlaping_bnd_id) &&
9138  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9139  {
9140  // Is the node living in a non overlapped boundary
9141  if (bb != internal_overlaping_bnd_id)
9142  {
9143  is_node_living_in_non_overlapped_boundary = true;
9144  }
9145 
9146  // Now we need to check that the node lies on a boundary
9147  // that still exist (the elements associated to the
9148  // boundary may have been removed at the mesh distribution
9149  // stage). The node may be still marked as a boundary node
9150  // but the boundary may not have elements associated.
9151 
9152  // Get the number of elements in the boundary
9153  const unsigned n_bound_ele = this->nboundary_element(bb);
9154  if (n_bound_ele > 0)
9155  {
9156  // Check that node lies on a nonhalo element, those are
9157  // the elements used to update the domain representation
9158  for (unsigned e = 0; e < n_bound_ele; e++)
9159  {
9160  // Get the boundary bulk element
9161  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9162  // Check if the element will be retained, it means it
9163  // is a nonhalo element
9164  std::set<FiniteElement*>::iterator it =
9165  element_in_processor_pt.find(bulk_ele_pt);
9166  // If found then check if the node live in the element
9167  if (it != element_in_processor_pt.end())
9168  {
9169  // Found the node in the nonhalo face element
9170  bool found_node = false;
9171  // Get the face index
9172  int face_index = this->face_index_at_boundary(bb, e);
9173  // Create the face element
9174  FiniteElement* face_ele_pt =
9175  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9176  // Get the number of nodes in the face element
9177  const unsigned n_node_face = face_ele_pt->nnode();
9178  // Get the first and last node of the face element
9179  Node* first_node_pt = face_ele_pt->node_pt(0);
9180  Node* last_node_pt = face_ele_pt->node_pt(n_node_face - 1);
9181  // Create the edge with the pair of nodes
9182  std::pair<Node*, Node*> tmp_edge =
9183  std::make_pair(first_node_pt, last_node_pt);
9184  // Check if the face element edge is overlapped by a
9185  // shared boundary
9186  // Is the face not overlapped?
9187  if (!overlapped_face[tmp_edge])
9188  {
9189  // Look for the node in the current face element
9190  for (unsigned n = 0; n < n_node_face; n++)
9191  {
9192  // Check for every individual node
9193  if (face_ele_pt->node_pt(n) == new_node_pt)
9194  {
9195  found_node = true;
9196  break;
9197  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9198  } // for (n < n_node_face)
9199  } // if (!overlapped_face[tmp_edge])
9200  // Free the memory of the face element
9201  delete face_ele_pt;
9202  if (found_node)
9203  {
9204  // return the first original boundary id found,
9205  // does not matter if the node lies on more than
9206  // one original boundary (with boundary
9207  // elements). This is the original boundary id
9208  // that will be used to create the connection
9209  flag_to_return = bb;
9210  return flag_to_return;
9211  } // if (found_node)
9212 
9213  } // if (it!=element_in_processor_pt.end())
9214 
9215  } // for (e < n_bound_ele)
9216 
9217  } // if (n_bound_ele > 0)
9218 
9219  } // if (bb != internal_overlaping_bnd_id ||
9220  // ((bb == internal_overlaping_bnd_id) &&
9221  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9222 
9223  } // if (nod_pt->is_on_boundary(bb))
9224 
9225  } // if (overlapping_internal_boundary)
9226  else
9227  {
9228  // Is the node on boundary bb?
9229  if (new_node_pt->is_on_boundary(bb))
9230  {
9231  // Now we need to check that the node lies on a boundary
9232  // that still exist (the elements associated to the boundary
9233  // may have been removed at the mesh distribution
9234  // stage). The node may be still marked as a boundary node
9235  // but the boundary may not have elements associated.
9236 
9237  // Get the number of elements in the boundary
9238  const unsigned n_bound_ele = this->nboundary_element(bb);
9239  if (n_bound_ele > 0)
9240  {
9241  // Check that node lies on a nonhalo element, those are
9242  // the elements used to update the domain representation
9243  for (unsigned e = 0; e < n_bound_ele; e++)
9244  {
9245  // Get the boundary bulk element
9246  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9247  // Check if the element will be retained, it means it is
9248  // a nonhalo element
9249  std::set<FiniteElement*>::iterator it =
9250  element_in_processor_pt.find(bulk_ele_pt);
9251  // If found then check if the node live in the element
9252  if (it != element_in_processor_pt.end())
9253  {
9254  // Found the node in the nonhalo face element
9255  bool found_node = false;
9256  // Get the face index
9257  int face_index = this->face_index_at_boundary(bb, e);
9258  // Create the face element
9259  FiniteElement* face_ele_pt =
9260  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9261  // Get the number of nodes in the face element
9262  const unsigned n_node_face = face_ele_pt->nnode();
9263  // Get the first and last node of the face element
9264  Node* first_node_pt = face_ele_pt->node_pt(0);
9265  Node* last_node_pt = face_ele_pt->node_pt(n_node_face - 1);
9266  // Create the edge with the pair of nodes
9267  std::pair<Node*, Node*> tmp_edge =
9268  std::make_pair(first_node_pt, last_node_pt);
9269  // Check if the face element edge is overlapped by a
9270  // shared boundary
9271  // Is the face not overlapped?
9272  if (!overlapped_face[tmp_edge])
9273  {
9274  // Look for the node in the current face element
9275  for (unsigned n = 0; n < n_node_face; n++)
9276  {
9277  // Check for every individual node
9278  if (face_ele_pt->node_pt(n) == new_node_pt)
9279  {
9280  found_node = true;
9281  break;
9282  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9283  } // for (n < n_node_face)
9284  } // if (!overlapped_face[tmp_edge])
9285  // Free the memory of the face element
9286  delete face_ele_pt;
9287  if (found_node)
9288  {
9289  // return the first original boundary id found, does
9290  // not matter if the node lies on more than one
9291  // original boundary (with boundary elements). This
9292  // is the original boundary id that will be used to
9293  // create the connection
9294  flag_to_return = bb;
9295  return flag_to_return;
9296  } // if (found_node)
9297 
9298  } // if (it!=element_in_processor_pt.end())
9299 
9300  } // for (e < n_bound_ele)
9301 
9302  } // if (n_bound_ele > 0)
9303 
9304  } // if (nod_pt->is_on_boundary(bb))
9305  } // else if (overlapping_internal_boundary)
9306  } // for (bb < noriginal_bnd)
9307 
9308  // We will only reach this stage when the node was found to be
9309  // connected to an original boundary but the element(s) on that
9310  // boundary where the node should live are not part of the domain.
9311  // Think in a corner of a triangle which touches the boundary
9312  // which elements will not be part of the domain
9313 
9314  // We need to break the currently forming polyline
9315  // flag_to_return = -3;
9316 
9317  // We need to break the currently forming polyline if and only if
9318  // the boundary(ies) in which the node is living is(are) not an
9319  // overlapped boundary
9320  if (!overlapping_internal_boundary)
9321  {
9322  // If the boundary(ies) in which the node is living is(are) an
9323  // overlapped boundary then break the break the formation of the
9324  // polyline
9325  flag_to_return = -3;
9326  }
9327  else
9328  {
9329  // The boundary is overlapped, if the node lives in a non
9330  // overlapped boundary then we can break the formation of the
9331  // polyline
9332  if (is_node_living_in_non_overlapped_boundary)
9333  {
9334  flag_to_return = -3;
9335  } // if (is_node_living_in_non_overlapped_boundar)y
9336 
9337  } // if (!overlapping_internal_boundary)
9338 
9339  } // if (new_node_pt->is_on_boundary())
9340 
9341  // Return inmediately if the connection is with an original boundary
9342  // whose elements are still part of the domain
9343  if (flag_to_return >= 0)
9344  {
9345  return flag_to_return;
9346  }
9347 
9348  // ----------------------------------------------------------------------
9349  // Secondly, if there is not a connection with any original
9350  // boundary, or if there is connection but with an original boundary
9351  // whose elements are not part of the domain, then check for
9352  // connections with previously created shared polylines
9353  // ----------------------------------------------------------------------
9354  // Store all the previous shared polylines to which the current
9355  // found is found to be connected
9356  Vector<unsigned> candidate_shared_bnd_to_connect;
9357  // Check for all the previous polylines except the current one
9358  for (std::map<unsigned, std::list<Node*>>::iterator it =
9359  shared_bnd_id_to_sorted_list_node_pt.begin();
9360  it != shared_bnd_id_to_sorted_list_node_pt.end();
9361  it++)
9362  {
9363  // Get the boundary id of the list of nodes that created the
9364  // polyline (the shared boundary id associated with the list of
9365  // nodes)
9366  const unsigned i_bnd_id = (*it).first;
9367  // Get an iterator pointer to the list of nodes of the shared
9368  // polyline
9369  std::list<Node*>::iterator it_list = (*it).second.begin();
9370  // Get the total number of nodes associated to the boundary
9371  const unsigned n_nodes = (*it).second.size();
9372  // Search for connections in the list of nodes
9373  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9374  {
9375  // Is the node already part of any other shared boundary
9376  if ((*it_list) == new_node_pt)
9377  {
9378  // Include the i-th boundary id in the list of candidate
9379  // shared boundaries to connect
9380  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9381  // Break the look with the i-th shared boundary, check with
9382  // the others shared boundaries
9383  break;
9384  } // if ((*it_list) == new_node_pt)
9385 
9386  } // for (i < nnodes)
9387 
9388  } // Loop over the shared boundaries and associated nodes
9389 
9390  // Get the number of candidate shared boundaries to connect
9391  const unsigned n_candidate_shared_bnd_to_connect =
9392  candidate_shared_bnd_to_connect.size();
9393 
9394  // Is there a connection with any previous shared polyline
9395  if (n_candidate_shared_bnd_to_connect > 0)
9396  {
9397  // If called from load balance we do not need to check if the
9398  // shared boundary is part of the processor since it certanily is,
9399  // only the shared boundaries that are pare of the processor are
9400  // used to created connection when creating the new shared
9401  // boundaries in the load balance rutine
9402  if (called_from_load_balance)
9403  {
9404  return candidate_shared_bnd_to_connect[0];
9405  }
9406 
9407  // We need to ensure that the shared boundary to which we are
9408  // connecting is part of the current processor, if none of the
9409  // found shared bundaries is in the current processor then return
9410  // the flag for "connection with boundary not in the current
9411  // processor"
9412 
9413  // Store the shared boundaries associated with the current processor
9414  Vector<unsigned> shared_bound_in_this_proc;
9415 
9416  // Get the shared boundaries associated with the current processor
9417  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9418 
9419  // If any of the candidate shared boundaries to connect is in the
9420  // current processor then return that shared boundary id
9421 
9422  // The number of shared boundaries in the current processor
9423  const unsigned n_shared_bound_in_this_proc =
9424  shared_bound_in_this_proc.size();
9425 
9426  // Loop over the candidate shared boundaries to connect
9427  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9428  {
9429  // Get the i-th candidate shared boundary to connect
9430  const unsigned i_candidate_shared_bnd =
9431  candidate_shared_bnd_to_connect[i];
9432 
9433  // Loop over the shared boundaries in the current processor
9434  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9435  {
9436  // Is the candidate boundary a shared boundary in this processor?
9437  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9438  {
9439  // Return the candidate shared boundary
9440  flag_to_return = i_candidate_shared_bnd;
9441  return flag_to_return;
9442  } // The candidate shared boundary is a boundary in the
9443  // current processor
9444 
9445  } // for (j < n_shared_bound_in_this_proc)
9446 
9447  } // for (i < n_candidate_shared_bnd_to_connect)
9448 
9449  // If non of the candidate shared boundaries to connect is in the
9450  // current processor the mark that we need to stop the addition of
9451  // vertices at this side of the polyline
9452  flag_to_return = -3;
9453 
9454  } // if (n_candidate_shared_bnd_to_connect > 0)
9455 
9456  // Return inmediately if the connection is with a previuos shared
9457  // boundary
9458  if (flag_to_return >= 0)
9459  {
9460  return flag_to_return;
9461  }
9462 
9463  // ------------------------------------------------------------------
9464  // Finally,check for connections with the same polyline (the shared
9465  // boundary that is being constructed). We are trying to avoid loops
9466  // or connections with the same shared boundary that is why this is
9467  // checked at the end
9468  // ------------------------------------------------------------------
9469  unsigned nrepeated = 0;
9470  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9471  it_list != current_polyline_nodes.end();
9472  it_list++)
9473  {
9474  // There must be at least one repeated node (the one that we have
9475  // just added, and it should be the first or last node)
9476  if ((*it_list) == new_node_pt)
9477  {
9478  nrepeated++;
9479  }
9480  }
9481  // If the number of repeated nodes is greater than one then the
9482  // polyline has a connection with itself
9483  if (nrepeated > 1)
9484  {
9485  // Return the flag value to indicate connection with itself, we
9486  // can not return the boundary id of the current polyline since it
9487  // has not been already assigned
9488  flag_to_return = -2;
9489  }
9490 
9491  // If there is no connection at all check the degree of the node, if
9492  // it is greater than 2 then return the flag to stop adding nodes
9493  // after this one
9494  if (node_degree > 2)
9495  {
9496  flag_to_return = -3;
9497  }
9498 
9499  // Return the flag
9500  return flag_to_return;
9501  }
9502 
9503  //======================================================================
9504  // \short Establish the connections of the polylines previously
9505  // marked as having connections. This connections were created in the
9506  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9507  // In case of doing load balancing the connections were created by the
9508  // function RefineableTriangleMesh::create_new_shared_boundaries()
9509  // ======================================================================
9510  template<class ELEMENT>
9512  {
9513  // Get the rank of the current processor
9514  const unsigned my_rank = this->communicator_pt()->my_rank();
9515 
9516  // Get the shared curves associated with this processor
9517  Vector<Vector<TriangleMeshPolyLine*>> shared_curves_pt =
9518  this->Shared_boundary_polyline_pt[my_rank];
9519 
9520  // Loop through the shared boundaries on the current processor and
9521  // check if they are marked to create a connection
9522  const unsigned ncurves = shared_curves_pt.size();
9523  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9524  {
9525  // Get the number of polylines in the current shared curve
9526  const unsigned npoly = shared_curves_pt[icurve].size();
9527  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9528  {
9529  // Get the polyline representation of the shared boundary
9530  TriangleMeshPolyLine* shd_poly_pt = shared_curves_pt[icurve][ipoly];
9531 
9532  // Get the boundary id of the current polyline
9533  const unsigned bound_id = shd_poly_pt->boundary_id();
9534 
9535  // Is the left vertex connected
9536  const bool is_connected_to_the_left =
9537  shd_poly_pt->is_initial_vertex_connected();
9538 
9539  // Is the right vertex connected
9540  const bool is_connected_to_the_right =
9541  shd_poly_pt->is_final_vertex_connected();
9542 
9543  // -----------------------------------------------------------------
9544  // If there is a connection at one of the ends we need to
9545  // establish that connection
9546  if (is_connected_to_the_left || is_connected_to_the_right)
9547  {
9548  // Now get the new left and right vertices of the shared
9549  // polyline
9550  const unsigned n_vertex = shd_poly_pt->nvertex();
9551 
9552  // Now get the polylines to where the current shared boundary is
9553  // connected and create the connections
9554 
9555  // --------------------------------------------------------------
9556  // Connection to the left
9557  if (is_connected_to_the_left)
9558  {
9559  // Get the unsigned version of the bound id to connect to
9560  // the left
9561  const unsigned uconnection_to_the_left =
9562  shd_poly_pt->initial_vertex_connected_bnd_id();
9563 
9564  // The pointer to the boundary to connect
9565  TriangleMeshPolyLine* poly_to_connect_pt = 0;
9566 
9567  // Flag to indicate we are trying to connect to an split
9568  // boundary
9569  bool connecting_to_an_split_boundary = false;
9570 
9571  // Flag to indicate we are trying to connecto to an internal
9572  // boundary that is overlaped by a shared boundary
9573  bool connecting_to_an_overlaped_boundary = false;
9574 
9575  // Check if the connection is with itself
9576  if (uconnection_to_the_left == bound_id)
9577  {
9578  // Set the pointer to the polyline to connect
9579  poly_to_connect_pt = shd_poly_pt;
9580  }
9581  else
9582  {
9583  // Get the initial shared boundary ids
9584  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9585  // Check if the boundary to connect is a shared polyline
9586  if (uconnection_to_the_left >= initial_shd_bnd_id)
9587  {
9588  // Get the polyline pointer representing the destination
9589  // boundary
9590  poly_to_connect_pt =
9591  boundary_polyline_pt(uconnection_to_the_left);
9592  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9593  else
9594  {
9595  // If we are going to connect to an original boundary
9596  // verify if the boundary was splitted during the
9597  // distribution process to consider all the chunks
9598  // (sub-polylines) of the boundary
9599  if (boundary_was_splitted(uconnection_to_the_left))
9600  {
9601  connecting_to_an_split_boundary = true;
9602  } // if (boundary_was_splitted(uconnection_to_the_left))
9603 
9604  // If we are going to connect to an original boundary
9605  // verify if the boundary, or any of its chunks is
9606  // marked to be overlapped by a shared boundary, if that
9607  // is the case we first check for connections in the
9608  // shared boundary that overlaps the internal boundary,
9609  // or the chunks, and then check for connections in the
9610  // original boundary
9611  if (connecting_to_an_split_boundary)
9612  {
9613  // Get the number of chucks that represent the
9614  // destination boundary
9615  const unsigned n_sub_poly =
9616  nboundary_subpolylines(uconnection_to_the_left);
9617  // Now loop over the chunks of the destination
9618  // boundary and if any of them is marked to be
9619  // overlaped by a shared boundary then set the flag
9620  // and break the loop
9621  for (unsigned ii = 0; ii < n_sub_poly; ii++)
9622  {
9623  if (boundary_marked_as_shared_boundary(
9624  uconnection_to_the_left, ii))
9625  {
9626  // Mark the boundary as being overlaped by a
9627  // shared boundary
9628  connecting_to_an_overlaped_boundary = true;
9629  // Break, no need to look for more overlapings
9630  break;
9631  } // if (boundary_marked_as_shared_boundary(...))
9632  } // for (ii < n_sub_poly)
9633  } // if (connecting_to_an_split_boundary)
9634  else
9635  {
9636  // If not connecting to an split boundary then check
9637  // if the whole destination boundary is overlaped by
9638  // an internal boundary
9639  if (boundary_marked_as_shared_boundary(
9640  uconnection_to_the_left, 0))
9641  {
9642  // Mark the boundary as being overlaped by a shared
9643  // boundary
9644  connecting_to_an_overlaped_boundary = true;
9645  } // if (boundary_marked_as_shared_boundary(...))
9646  } // else if (connecting_to_an_split_boundary)
9647 
9648  // If we are connecting neither to an split boundary nor
9649  // an overlaped boundary then get the pointer to the
9650  // original boundary
9651  if (!(connecting_to_an_split_boundary ||
9652  connecting_to_an_overlaped_boundary))
9653  {
9654  // Get the polyline pointer representing the
9655  // destination boundary
9656  poly_to_connect_pt =
9657  boundary_polyline_pt(uconnection_to_the_left);
9658  } // else if (NOT split, NOT overlaped)
9659  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9660 
9661  } // else if (uconnection_to_the_left == bound_id)
9662 
9663 #ifdef PARANOID
9664  // If we are not connecting to an original boundary
9665  // (connecting to the same shared boundary or to another
9666  // shared boundary) then the boundary should not be marked
9667  // as split
9668  if (!connecting_to_an_split_boundary)
9669  {
9670  if (boundary_was_splitted(uconnection_to_the_left))
9671  {
9672  std::stringstream error;
9673  error
9674  << "The current shared boundary (" << bound_id << ") was "
9675  << "marked to have a connection\nto the left with the "
9676  << "boundary (" << uconnection_to_the_left << ").\n"
9677  << "The problem is that the destination boundary (possibly\n"
9678  << "another shared boundary) is marked to be split\n"
9679  << "There should not be split shared boundaries\n\n";
9680  throw OomphLibError(
9681  error.str(),
9682  "TriangleMesh::create_shared_polylines_connections()",
9683  OOMPH_EXCEPTION_LOCATION);
9684  }
9685  } // if (!connecting_to_an_split_boundary)
9686 #endif
9687 
9688  // Now look for the vertex number on the destination
9689  // boundary(ies) -- in case that the boundary was split ---
9690 
9691  // Do not check for same orientation, that was previously
9692  // worked by interchanging the connections boundaries (if
9693  // necessary)
9694 
9695  // Get the left vertex in the shared boundary
9696  Vector<double> shd_bnd_left_vertex =
9697  shd_poly_pt->vertex_coordinate(0);
9698 
9699  // If the boundary was not split then ...
9700  if (!connecting_to_an_split_boundary)
9701  {
9702  // ... check if the boundary is marked to be overlaped by
9703  // a shared boundary
9704  if (!connecting_to_an_overlaped_boundary)
9705  {
9706  // If that is not the case then we can safely look for
9707  // the vertex number on the destination boundar
9708  unsigned vertex_index = 0;
9709 
9710  const bool found_vertex_index =
9711  get_connected_vertex_number_on_destination_polyline(
9712  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9713 
9714  // If we could not find the vertex index to connect then
9715  // we are in trouble
9716  if (!found_vertex_index)
9717  {
9718  std::stringstream error;
9719  error
9720  << "The current shared boundary (" << bound_id << ") was "
9721  << "marked to have a connection\nto the left with the "
9722  << "boundary (" << uconnection_to_the_left << ").\n"
9723  << "The problem is that the left vertex of the current\n"
9724  << "shared boundary is not in the list of vertices of the\n"
9725  << "boundary to connect.\n\n"
9726  << "This is the left vertex of the current shared "
9727  "boundary\n"
9728  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9729  << shd_bnd_left_vertex[1] << ")\n\n"
9730  << "This is the list of vertices on the destination "
9731  << "boundary\n";
9732  const unsigned n_v = poly_to_connect_pt->nvertex();
9733  for (unsigned i = 0; i < n_v; i++)
9734  {
9735  Vector<double> cvertex =
9736  poly_to_connect_pt->vertex_coordinate(i);
9737  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9738  << cvertex[1] << ")\n";
9739  }
9740  throw OomphLibError(
9741  error.str(),
9742  "TriangleMesh::create_shared_polylines_connections()",
9743  OOMPH_EXCEPTION_LOCATION);
9744  } // if (!found_vertex_index)
9745 
9746  // Create the connection, the left vertex of the current
9747  // shared boundary is connected with the vertex_index-th
9748  // vertex on the destination boundary
9749  shd_poly_pt->connect_initial_vertex_to_polyline(
9750  poly_to_connect_pt, vertex_index);
9751 
9752  } // if (!connecting_to_an_overlaped_boundary)
9753  else
9754  {
9755  // If the boundary is marked to be overlaped by a shared
9756  // boundary then get that shared boundary and look for
9757  // the connection in that boundary
9758 
9759  // The vertex where to store the index to connect
9760  unsigned vertex_index = 0;
9761  // A flag to indicate if the connection was found
9762  bool found_vertex_index = false;
9763 
9764  // Get the shared boundary id that is overlaping the
9765  // internal boundary
9766  Vector<unsigned> dst_shd_bnd_ids;
9767  get_shared_boundaries_overlapping_internal_boundary(
9768  uconnection_to_the_left, dst_shd_bnd_ids);
9769 
9770  // Get the number of shared polylines that were found to
9771  // overlap the internal boundary
9772  const unsigned n_shd_bnd_overlap_int_bnd =
9773  dst_shd_bnd_ids.size();
9774 
9775  // Loop over the shared boundaries that overlap the
9776  // internal boundary and look for the vertex to connect
9777  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9778  {
9779  // Get the shared polyline
9780  const unsigned new_connection_to_the_left =
9781  dst_shd_bnd_ids[ss];
9782 
9783  // Get the shared polyline that is overlaping the
9784  // internal boundary
9785  poly_to_connect_pt =
9786  boundary_polyline_pt(new_connection_to_the_left);
9787 
9788  if (poly_to_connect_pt != 0)
9789  {
9790  // Look for the vertex number in the destination
9791  // shared polyline
9792  found_vertex_index =
9793  get_connected_vertex_number_on_destination_polyline(
9794  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9795  } // if (poly_to_connect_pt!=0)
9796 
9797  // If we have found the vertex to connect then
9798  // break the loop
9799  if (found_vertex_index)
9800  {
9801  break;
9802  } // if (found_vertex_index)
9803 
9804  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9805 
9806 #ifdef PARANOID
9807  // If we could not find the vertex index to connect then
9808  // we are in trouble
9809  if (!found_vertex_index)
9810  {
9811  std::stringstream error;
9812  error
9813  << "The current shared boundary (" << bound_id << ") was "
9814  << "marked to have a connection\nto the left with the "
9815  << "boundary (" << uconnection_to_the_left << ").\n"
9816  << "This last boundary is marked to be overlaped by "
9817  << "shared boundaries\n"
9818  << "The problem is that the left vertex of the current\n"
9819  << "shared boundary is not in the list of vertices of the\n"
9820  << "boundary to connect.\n\n"
9821  << "This is the left vertex of the current shared "
9822  "boundary\n"
9823  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9824  << shd_bnd_left_vertex[1] << ")\n\n"
9825  << "This is the list of vertices on the destination "
9826  << "boundary\n";
9827  Vector<unsigned> dst_shd_bnd_ids;
9828  get_shared_boundaries_overlapping_internal_boundary(
9829  uconnection_to_the_left, dst_shd_bnd_ids);
9830  const unsigned n_shd_bnd_overlap_int_bnd =
9831  dst_shd_bnd_ids.size();
9832  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9833  {
9834  const unsigned new_connection_to_the_left =
9835  dst_shd_bnd_ids[ss];
9836  poly_to_connect_pt =
9837  boundary_polyline_pt(new_connection_to_the_left);
9838  if (poly_to_connect_pt != 0)
9839  {
9840  const unsigned shd_bnd_id_overlap =
9841  poly_to_connect_pt->boundary_id();
9842  error << "Shared boundary id(" << shd_bnd_id_overlap
9843  << ")\n";
9844  const unsigned n_v = poly_to_connect_pt->nvertex();
9845  for (unsigned i = 0; i < n_v; i++)
9846  {
9847  Vector<double> cvertex =
9848  poly_to_connect_pt->vertex_coordinate(i);
9849  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9850  << cvertex[1] << ")\n";
9851  }
9852  } // if (poly_to_connect_pt != 0)
9853  } // for (ss < n_shd_bnd_overlap_int_bnd)
9854 
9855  throw OomphLibError(
9856  error.str(),
9857  "TriangleMesh::create_shared_polylines_connections()",
9858  OOMPH_EXCEPTION_LOCATION);
9859 
9860  } // if (!found_vertex_index)
9861 #endif
9862 
9863  // Create the connection, the left vertex of the current
9864  // shared boundary is connected with the vertex_index-th
9865  // vertex on the destination boundary
9866  shd_poly_pt->connect_initial_vertex_to_polyline(
9867  poly_to_connect_pt, vertex_index);
9868 
9869  } // else if (!connecting_to_an_overlaped_boundary)
9870 
9871  } // if (!connecting_to_an_split_boundary)
9872  else
9873  {
9874  // If the boundary was split then we need to look for the
9875  // vertex in the sub-polylines
9876 
9877  // Get the sub-polylines vector
9878  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9879  boundary_subpolylines(uconnection_to_the_left);
9880 
9881  // Get the number of sub-polylines
9882  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9883 #ifdef PARANOID
9884  if (nsub_poly <= 1)
9885  {
9886  std::ostringstream error_message;
9887  error_message
9888  << "The boundary (" << uconnection_to_the_left << ") was "
9889  << "marked to be splitted but\n"
9890  << "there are only (" << nsub_poly << ") polylines to "
9891  << "represent it.\n";
9892  throw OomphLibError(
9893  error_message.str(),
9894  "TriangleMesh::create_shared_polylines_connections()",
9895  OOMPH_EXCEPTION_LOCATION);
9896  } // if (nsub_poly <= 1)
9897 #endif
9898  // We need to check if the boundary is marked to be
9899  // overlaped by an internal boundary, if that is the case
9900  // we need to check for each indivual subpolyline, and for
9901  // those overlaped by a shared polyline look for the
9902  // vertex in the shared polyline representation instead of
9903  // the original subpolyline
9904 
9905  // ... check if the boundary is marked to be overlaped by
9906  // a shared boundary
9907  if (!connecting_to_an_overlaped_boundary)
9908  {
9909  // We can work without checking the subpolylines
9910  // individually
9911 
9912  // The vertex where to store the index to connect
9913  unsigned vertex_index = 0;
9914  // The subpoly number to connect
9915  unsigned sub_poly_to_connect = 0;
9916  // A flag to indicate if the connection was found
9917  bool found_vertex_index = false;
9918 
9919  // Look for the vertex number to connect on each of the
9920  // subpolyines
9921  for (unsigned isub = 0; isub < nsub_poly; isub++)
9922  {
9923  // Assign the pointer to the sub-polyline
9924  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9925  // Search for the vertex in the current sub-polyline
9926  found_vertex_index =
9927  get_connected_vertex_number_on_destination_polyline(
9928  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9929  // If we have found the vertex to connect then break the
9930  // loop
9931  if (found_vertex_index)
9932  {
9933  // But first save the subpoly number (chunk), that
9934  // will be used to perform the connection
9935  sub_poly_to_connect = isub;
9936  break;
9937  } // if (found_vertex_index)
9938  } // for (isub < nsub_poly)
9939 
9940 #ifdef PARANOID
9941  // If we could not find the vertex index to connect then
9942  // we are in trouble
9943  if (!found_vertex_index)
9944  {
9945  std::stringstream error;
9946  error
9947  << "The current shared boundary (" << bound_id << ") was "
9948  << "marked to have a connection\nto the left with the "
9949  << "boundary (" << uconnection_to_the_left << ").\n"
9950  << "The problem is that the left vertex of the current\n"
9951  << "shared boundary is not in the list of vertices of any\n"
9952  << "of the sub polylines that represent the boundary to\n"
9953  << "connect.\n\n"
9954  << "This is the left vertex of the current shared "
9955  "boundary\n"
9956  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9957  << shd_bnd_left_vertex[1] << ")\n\n"
9958  << "This is the list of vertices on the destination "
9959  << "boundary\n";
9960  for (unsigned p = 0; p < nsub_poly; p++)
9961  {
9962  error << "Subpolyline #(" << p << ")\n";
9963  poly_to_connect_pt = tmp_vector_subpolylines[p];
9964  const unsigned n_v = poly_to_connect_pt->nvertex();
9965  for (unsigned i = 0; i < n_v; i++)
9966  {
9967  Vector<double> cvertex =
9968  poly_to_connect_pt->vertex_coordinate(i);
9969  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9970  << cvertex[1] << ")\n";
9971  }
9972  } // for (p < nsub_poly)
9973  throw OomphLibError(
9974  error.str(),
9975  "TriangleMesh::create_shared_polylines_connections()",
9976  OOMPH_EXCEPTION_LOCATION);
9977  } // if (!found_vertex_index)
9978 #endif
9979 
9980  // Create the connection, the left vertex of the current
9981  // shared boundary is connected with the vertex_index-th
9982  // vertex of sub_poly_to_connect-th subpolyline of the
9983  // destination boundary
9984  shd_poly_pt->connect_initial_vertex_to_polyline(
9985  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9986 
9987  } // if (!connecting_to_an_overlaped_boundary)
9988  else
9989  {
9990  // We first look on the shared boundaries that overlap
9991  // the internal boundaries and the look for the
9992  // sub-polylines that are not marked as being overlaped
9993  // by shared boundaries
9994 
9995  // The vertex where to store the index to connect
9996  unsigned vertex_index = 0;
9997  // The subpoly number to connect
9998  unsigned sub_poly_to_connect = 0;
9999  // A flag to indicate if the connection was found
10000  bool found_vertex_index = false;
10001 
10002  // Get the shared boundaries id that are overlaping the
10003  // internal boundary
10004  Vector<unsigned> dst_shd_bnd_ids;
10005  get_shared_boundaries_overlapping_internal_boundary(
10006  uconnection_to_the_left, dst_shd_bnd_ids);
10007 
10008  // Get the number of shared polylines that were found to
10009  // overlap the internal boundary
10010  const unsigned n_shd_bnd_overlap_int_bnd =
10011  dst_shd_bnd_ids.size();
10012 
10013  // Loop over the shared boundaries that overlap the
10014  // internal boundary and look for the vertex to connect
10015  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10016  {
10017  // Get the shared polyline
10018  const unsigned new_connection_to_the_left =
10019  dst_shd_bnd_ids[ss];
10020 
10021  // Make sure that the destination polyline is not the
10022  // same as the current shared polyline
10023  if (bound_id != new_connection_to_the_left)
10024  {
10025  // Get the shared polyline that is overlaping the
10026  // internal boundary
10027  poly_to_connect_pt =
10028  boundary_polyline_pt(new_connection_to_the_left);
10029 
10030  if (poly_to_connect_pt != 0)
10031  {
10032  // Look for the vertex number in the destination
10033  // shared polyline
10034  found_vertex_index =
10035  get_connected_vertex_number_on_destination_polyline(
10036  poly_to_connect_pt,
10037  shd_bnd_left_vertex,
10038  vertex_index);
10039  } // if (poly_to_connect_pt != 0)
10040 
10041  // If we have found the vertex to connect then
10042  // break the loop
10043  if (found_vertex_index)
10044  {
10045  break;
10046  } // if (found_vertex_index)
10047 
10048  } // if (bound_id != new_connection_to_the_left)
10049 
10050  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10051 
10052  // If we have not yet found the vertex then look for it
10053  // in the sub-polylines that are not overlaped by shared
10054  // boundaries
10055  if (!found_vertex_index)
10056  {
10057  // Look for the vertex number to connect on each of
10058  // the subpolyines
10059  for (unsigned isub = 0; isub < nsub_poly; isub++)
10060  {
10061  // Only work with those sub-polylines that are not
10062  // overlaped by shared boundaries
10063  if (!boundary_marked_as_shared_boundary(
10064  uconnection_to_the_left, isub))
10065  {
10066  // Assign the pointer to the sub-polyline
10067  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10068  // Search for the vertex in the current sub-polyline
10069  found_vertex_index =
10070  get_connected_vertex_number_on_destination_polyline(
10071  poly_to_connect_pt,
10072  shd_bnd_left_vertex,
10073  vertex_index);
10074  // If we have found the vertex to connect then break the
10075  // loop
10076  if (found_vertex_index)
10077  {
10078  // But first save the subpoly number (chunk), that
10079  // will be used to perform the connection
10080  sub_poly_to_connect = isub;
10081  break;
10082  } // if (found_vertex_index)
10083 
10084  } // if (not overlaped by shared boundary)
10085 
10086  } // for (isub < nsub_poly)
10087 
10088  } // if (!found_vertex_index)
10089 
10090 #ifdef PARANOID
10091  // If we could not find the vertex index to connect then
10092  // we are in trouble
10093  if (!found_vertex_index)
10094  {
10095  std::stringstream error;
10096  error
10097  << "The current shared boundary (" << bound_id << ") was "
10098  << "marked to have a connection\nto the left with the "
10099  << "boundary (" << uconnection_to_the_left << ").\n"
10100  << "This last boundary is marked to be overlaped by "
10101  << "shared boundaries\n"
10102  << "The problem is that the left vertex of the current\n"
10103  << "shared boundary is not in the list of vertices of "
10104  << "the\nboundary to connect.\n\n"
10105  << "This is the left vertex of the current shared "
10106  << "boundary\n"
10107  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
10108  << shd_bnd_left_vertex[1] << ")\n\n"
10109  << "This is the list of vertices on the destination "
10110  << "boundary (only those subpolylines not marked as "
10111  << "overlaped by\nshared boundaries)\n";
10112  for (unsigned p = 0; p < nsub_poly; p++)
10113  {
10114  if (!boundary_marked_as_shared_boundary(
10115  uconnection_to_the_left, p))
10116  {
10117  error << "Subpolyline #(" << p << ")\n";
10118  poly_to_connect_pt = tmp_vector_subpolylines[p];
10119  const unsigned n_v = poly_to_connect_pt->nvertex();
10120  for (unsigned i = 0; i < n_v; i++)
10121  {
10122  Vector<double> cvertex =
10123  poly_to_connect_pt->vertex_coordinate(i);
10124  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10125  << cvertex[1] << ")\n";
10126  }
10127  } // Not marked as overlaped
10128  } // for (p < nsub_poly)
10129  error << "\nThis is the list of vertices of the shared "
10130  << "polylines that overlap\nthe internal "
10131  << "boundary\n";
10132  Vector<unsigned> dst_shd_bnd_ids;
10133  get_shared_boundaries_overlapping_internal_boundary(
10134  uconnection_to_the_left, dst_shd_bnd_ids);
10135  const unsigned n_shd_bnd_overlap_int_bnd =
10136  dst_shd_bnd_ids.size();
10137  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10138  {
10139  const unsigned new_connection_to_the_left =
10140  dst_shd_bnd_ids[ss];
10141  poly_to_connect_pt =
10142  boundary_polyline_pt(new_connection_to_the_left);
10143  if (poly_to_connect_pt != 0)
10144  {
10145  const unsigned shd_bnd_id_overlap =
10146  poly_to_connect_pt->boundary_id();
10147  error << "Shared boundary id(" << shd_bnd_id_overlap
10148  << ")\n";
10149  const unsigned n_v = poly_to_connect_pt->nvertex();
10150  for (unsigned i = 0; i < n_v; i++)
10151  {
10152  Vector<double> cvertex =
10153  poly_to_connect_pt->vertex_coordinate(i);
10154  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10155  << cvertex[1] << ")\n";
10156  }
10157  } // if (poly_to_connect_pt != 0)
10158  } // for (ss < n_shd_bnd_overlap_int_bnd)
10159 
10160  throw OomphLibError(
10161  error.str(),
10162  "TriangleMesh::create_shared_polylines_connections()",
10163  OOMPH_EXCEPTION_LOCATION);
10164  } // if (!found_vertex_index)
10165 #endif
10166 
10167  // Create the connection, the left vertex of the current
10168  // shared boundary is connected with the vertex_index-th
10169  // vertex of sub_poly_to_connect-th subpolyline of the
10170  // destination boundary
10171  shd_poly_pt->connect_initial_vertex_to_polyline(
10172  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10173 
10174  } // else if (!connecting_to_an_overlaped_boundary)
10175 
10176  } // else if (!connecting_to_an_split_boundary)
10177 
10178  } // if (connection_to_the_left != -1)
10179 
10180  // --------------------------------------------------------------
10181  // Connection to the right
10182  if (is_connected_to_the_right)
10183  {
10184  // Get the unsigned version of the bound id to connect to
10185  // the right
10186  const unsigned uconnection_to_the_right =
10187  shd_poly_pt->final_vertex_connected_bnd_id();
10188 
10189  // The pointer to the boundary to connect
10190  TriangleMeshPolyLine* poly_to_connect_pt = 0;
10191 
10192  // Flag to indicate we are trying to connect to an split
10193  // boundary
10194  bool connecting_to_an_split_boundary = false;
10195 
10196  // Flag to indicate we are trying to connecto to an internal
10197  // boundary that is overlaped by a shared boundary
10198  bool connecting_to_an_overlaped_boundary = false;
10199 
10200  // Check if the connection is with itself
10201  if (uconnection_to_the_right == bound_id)
10202  {
10203  // Set the pointer to the polyline to connect
10204  poly_to_connect_pt = shd_poly_pt;
10205  }
10206  else
10207  {
10208  // Get the initial shared boundary ids
10209  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10210  // Check if the boundary to connect is a shared polyline
10211  if (uconnection_to_the_right >= initial_shd_bnd_id)
10212  {
10213  // Get the polyline pointer representing the destination
10214  // boundary
10215  poly_to_connect_pt =
10216  boundary_polyline_pt(uconnection_to_the_right);
10217  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10218  else
10219  {
10220  // If we are going to connect to an original boundary
10221  // verify if the boundary was splitted during the
10222  // distribution process to consider all the chunks
10223  // (sub-polylines) of the boundary
10224  if (boundary_was_splitted(uconnection_to_the_right))
10225  {
10226  connecting_to_an_split_boundary = true;
10227  } // if (boundary_was_splitted(uconnection_to_the_right))
10228 
10229  // If we are going to connect to an original boundary
10230  // verify if the boundary, or any of its chunks is
10231  // marked to be overlapped by a shared boundary, if that
10232  // is the case we first check for connections in the
10233  // shared boundary that overlaps the internal boundary,
10234  // or the chunks, and then check for connections in the
10235  // original boundary
10236  if (connecting_to_an_split_boundary)
10237  {
10238  // Get the number of chucks that represent the
10239  // destination boundary
10240  const unsigned n_sub_poly =
10241  nboundary_subpolylines(uconnection_to_the_right);
10242  // Now loop over the chunks of the destination
10243  // boundary and if any of them is marked to be
10244  // overlaped by a shared boundary then set the flag
10245  // and break the loop
10246  for (unsigned ii = 0; ii < n_sub_poly; ii++)
10247  {
10248  if (boundary_marked_as_shared_boundary(
10249  uconnection_to_the_right, ii))
10250  {
10251  // Mark the boundary as being overlaped by a
10252  // shared boundary
10253  connecting_to_an_overlaped_boundary = true;
10254  // Break, no need to look for more overlapings
10255  break;
10256  } // if (boundary_marked_as_shared_boundary(...))
10257  } // for (ii < n_sub_poly)
10258  } // if (connecting_to_an_split_boundary)
10259  else
10260  {
10261  // If not connecting to an split boundary then check
10262  // if the whole destination boundary is overlaped by
10263  // an internal boundary
10264  if (boundary_marked_as_shared_boundary(
10265  uconnection_to_the_right, 0))
10266  {
10267  // Mark the boundary as being overlaped by a shared
10268  // boundary
10269  connecting_to_an_overlaped_boundary = true;
10270  } // if (boundary_marked_as_shared_boundary(...))
10271  } // else if (connecting_to_an_split_boundary)
10272 
10273  // If we are connecting neither to an split boundary nor
10274  // an overlaped boundary then get the pointer to the
10275  // original boundary
10276  if (!(connecting_to_an_split_boundary ||
10277  connecting_to_an_overlaped_boundary))
10278  {
10279  // Get the polyline pointer representing the
10280  // destination boundary
10281  poly_to_connect_pt =
10282  boundary_polyline_pt(uconnection_to_the_right);
10283  } // else if (NOT split, NOT overlaped)
10284  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10285 
10286  } // else if (uconnection_to_the_right == bound_id)
10287 
10288 #ifdef PARANOID
10289  // If we are not connecting to an original boundary
10290  // (connecting to the same shared boundary or to another
10291  // shared boundary) then the boundary should not be marked
10292  // as split
10293  if (!connecting_to_an_split_boundary)
10294  {
10295  if (boundary_was_splitted(uconnection_to_the_right))
10296  {
10297  std::stringstream error;
10298  error
10299  << "The current shared boundary (" << bound_id << ") was "
10300  << "marked to have a connection\nto the right with the "
10301  << "boundary (" << uconnection_to_the_right << ").\n"
10302  << "The problem is that the destination boundary (possibly\n"
10303  << "another shared boundary) is marked to be split\n"
10304  << "There should not be split shared boundaries\n\n";
10305  throw OomphLibError(
10306  error.str(),
10307  "TriangleMesh::create_shared_polylines_connections()",
10308  OOMPH_EXCEPTION_LOCATION);
10309  }
10310  } // if (!connecting_to_an_split_boundary)
10311 #endif
10312 
10313  // Now look for the vertex number on the destination
10314  // boundary(ies) -- in case that the boundary was split ---
10315 
10316  // Do not check for same orientation, that was previously
10317  // worked by interchanging the connections boundaries (if
10318  // necessary)
10319 
10320  // Get the right vertex in the shared boundary
10321  Vector<double> shd_bnd_right_vertex =
10322  shd_poly_pt->vertex_coordinate(n_vertex - 1);
10323 
10324  // If the boundary was not split then inmediately look for
10325  // the vertex index in the destination boundary
10326  if (!connecting_to_an_split_boundary)
10327  {
10328  // ... check if the boundary is marked to be overlaped by
10329  // a shared boundary
10330  if (!connecting_to_an_overlaped_boundary)
10331  {
10332  // If that is not the case then we can safely look for
10333  // the vertex number on the destination boundar
10334 
10335  unsigned vertex_index = 0;
10336  const bool found_vertex_index =
10337  get_connected_vertex_number_on_destination_polyline(
10338  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10339 
10340  // If we could not find the vertex index to connect then
10341  // we are in trouble
10342  if (!found_vertex_index)
10343  {
10344  std::stringstream error;
10345  error
10346  << "The current shared boundary (" << bound_id << ") was "
10347  << "marked to have a connection\nto the right with the "
10348  << "boundary (" << uconnection_to_the_right << ").\n"
10349  << "The problem is that the right vertex of the current\n"
10350  << "shared boundary is not in the list of vertices of the\n"
10351  << "boundary to connect.\n\n"
10352  << "This is the right vertex of the current shared "
10353  "boundary\n"
10354  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10355  << shd_bnd_right_vertex[1] << ")\n\n"
10356  << "This is the list of vertices on the destination "
10357  "boundary\n";
10358  const unsigned n_v = poly_to_connect_pt->nvertex();
10359  for (unsigned i = 0; i < n_v; i++)
10360  {
10361  Vector<double> cvertex =
10362  poly_to_connect_pt->vertex_coordinate(i);
10363  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10364  << cvertex[1] << ")\n";
10365  }
10366  throw OomphLibError(
10367  error.str(),
10368  "TriangleMesh::create_shared_polylines_connections()",
10369  OOMPH_EXCEPTION_LOCATION);
10370  } // if (!found_vertex_index)
10371 
10372  // Create the connection, the right vertex of the current
10373  // shared boundary is connected with the vertex_index-th
10374  // vertex on the destination boundary
10375  shd_poly_pt->connect_final_vertex_to_polyline(
10376  poly_to_connect_pt, vertex_index);
10377 
10378  } // if (!connecting_to_an_overlaped_boundary)
10379  else
10380  {
10381  // If the boundary is marked to be overlaped by a shared
10382  // boundary then get that shared boundary and look for
10383  // the connection in that boundary
10384 
10385  // The vertex where to store the index to connect
10386  unsigned vertex_index = 0;
10387  // A flag to indicate if the connection was found
10388  bool found_vertex_index = false;
10389 
10390  // Get the shared boundary id that is overlaping the
10391  // internal boundary
10392  Vector<unsigned> dst_shd_bnd_ids;
10393  get_shared_boundaries_overlapping_internal_boundary(
10394  uconnection_to_the_right, dst_shd_bnd_ids);
10395 
10396  // Get the number of shared polylines that were found to
10397  // overlap the internal boundary
10398  const unsigned n_shd_bnd_overlap_int_bnd =
10399  dst_shd_bnd_ids.size();
10400 
10401  // Loop over the shared boundaries that overlap the
10402  // internal boundary and look for the vertex to connect
10403  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10404  {
10405  // Get the shared polyline
10406  const unsigned new_connection_to_the_right =
10407  dst_shd_bnd_ids[ss];
10408 
10409  // Get the shared polyline that is overlaping the
10410  // internal boundary
10411  poly_to_connect_pt =
10412  boundary_polyline_pt(new_connection_to_the_right);
10413 
10414  if (poly_to_connect_pt != 0)
10415  {
10416  // Look for the vertex number in the destination
10417  // shared polyline
10418  found_vertex_index =
10419  get_connected_vertex_number_on_destination_polyline(
10420  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10421  } // if (poly_to_connect_pt!=0)
10422 
10423  // If we have found the vertex to connect then
10424  // break the loop
10425  if (found_vertex_index)
10426  {
10427  break;
10428  } // if (found_vertex_index)
10429 
10430  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10431 
10432 #ifdef PARANOID
10433  // If we could not find the vertex index to connect then
10434  // we are in trouble
10435  if (!found_vertex_index)
10436  {
10437  std::stringstream error;
10438  error
10439  << "The current shared boundary (" << bound_id << ") was "
10440  << "marked to have a connection\nto the right with the "
10441  << "boundary (" << uconnection_to_the_right << ").\n"
10442  << "This last boundary is marked to be overlaped by "
10443  << "shared boundaries\n"
10444  << "The problem is that the right vertex of the current\n"
10445  << "shared boundary is not in the list of vertices of the\n"
10446  << "boundary to connect.\n\n"
10447  << "This is the right vertex of the current shared "
10448  "boundary\n"
10449  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10450  << shd_bnd_right_vertex[1] << ")\n\n"
10451  << "This is the list of vertices on the destination "
10452  << "boundary\n";
10453  Vector<unsigned> dst_shd_bnd_ids;
10454  get_shared_boundaries_overlapping_internal_boundary(
10455  uconnection_to_the_right, dst_shd_bnd_ids);
10456  const unsigned n_shd_bnd_overlap_int_bnd =
10457  dst_shd_bnd_ids.size();
10458  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10459  {
10460  const unsigned new_connection_to_the_right =
10461  dst_shd_bnd_ids[ss];
10462  poly_to_connect_pt =
10463  boundary_polyline_pt(new_connection_to_the_right);
10464  if (poly_to_connect_pt != 0)
10465  {
10466  const unsigned shd_bnd_id_overlap =
10467  poly_to_connect_pt->boundary_id();
10468  error << "Shared boundary id(" << shd_bnd_id_overlap
10469  << ")\n";
10470  const unsigned n_v = poly_to_connect_pt->nvertex();
10471  for (unsigned i = 0; i < n_v; i++)
10472  {
10473  Vector<double> cvertex =
10474  poly_to_connect_pt->vertex_coordinate(i);
10475  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10476  << cvertex[1] << ")\n";
10477  }
10478  } // if (poly_to_connect_pt != 0)
10479  } // for (ss < n_shd_bnd_overlap_int_bnd)
10480 
10481  throw OomphLibError(
10482  error.str(),
10483  "TriangleMesh::create_shared_polylines_connections()",
10484  OOMPH_EXCEPTION_LOCATION);
10485 
10486  } // if (!found_vertex_index)
10487 #endif
10488 
10489  // Create the connection, the right vertex of the
10490  // current shared boundary is connected with the
10491  // vertex_index-th vertex on the destination boundary
10492  shd_poly_pt->connect_final_vertex_to_polyline(
10493  poly_to_connect_pt, vertex_index);
10494 
10495  } // else if (!connecting_to_an_overlaped_boundary)
10496 
10497  } // if (!connecting_to_an_split_boundary)
10498  else
10499  {
10500  // If the boundary was split then we need to look for the
10501  // vertex in the sub-polylines
10502 
10503  // Get the sub-polylines vector
10504  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10505  boundary_subpolylines(uconnection_to_the_right);
10506 
10507  // Get the number of sub-polylines
10508  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10509 #ifdef PARANOID
10510  if (nsub_poly <= 1)
10511  {
10512  std::ostringstream error_message;
10513  error_message
10514  << "The boundary (" << uconnection_to_the_right << ") was "
10515  << "marked to be splitted but\n"
10516  << "there are only (" << nsub_poly << ") polylines to "
10517  << "represent it.\n";
10518  throw OomphLibError(
10519  error_message.str(),
10520  "TriangleMesh::create_shared_polylines_connections()",
10521  OOMPH_EXCEPTION_LOCATION);
10522  } // if (nsub_poly <= 1)
10523 #endif
10524 
10525  // We need to check if the boundary is marked to be
10526  // overlaped by an internal boundary, if that is the case
10527  // we need to check for each indivual subpolyline, and for
10528  // those overlaped by a shared polyline look for the
10529  // vertex in the shared polyline representation instead of
10530  // the original subpolyline
10531 
10532  // ... check if the boundary is marked to be overlaped by
10533  // a shared boundary
10534  if (!connecting_to_an_overlaped_boundary)
10535  {
10536  // We can work without checking the subpolylines
10537  // individually
10538 
10539  // The vertex where to store the index to connect
10540  unsigned vertex_index = 0;
10541  // The subpoly number to connect
10542  unsigned sub_poly_to_connect = 0;
10543  // A flag to indicate if the connection was found
10544  bool found_vertex_index = false;
10545 
10546  // Look for the vertex number to connect on each of the
10547  // subpolyines
10548  for (unsigned isub = 0; isub < nsub_poly; isub++)
10549  {
10550  // Assign the pointer to the sub-polyline
10551  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10552  // Search for the vertex in the current sub-polyline
10553  found_vertex_index =
10554  get_connected_vertex_number_on_destination_polyline(
10555  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10556  // If we have found the vertex to connect then break the
10557  // loop
10558  if (found_vertex_index)
10559  {
10560  // But first save the subpoly number (chunk), that
10561  // will be used to perform the connection
10562  sub_poly_to_connect = isub;
10563  break;
10564  } // if (found_vertex_index)
10565  } // for (isub < nsub_poly)
10566 
10567 #ifdef PARANOID
10568  // If we could not find the vertex index to connect then
10569  // we are in trouble
10570  if (!found_vertex_index)
10571  {
10572  std::stringstream error;
10573  error
10574  << "The current shared boundary (" << bound_id << ") was "
10575  << "marked to have a connection\nto the right with the "
10576  << "boundary (" << uconnection_to_the_right << ").\n"
10577  << "The problem is that the right vertex of the current\n"
10578  << "shared boundary is not in the list of vertices of any\n"
10579  << "of the sub polylines that represent the boundary to\n"
10580  << "connect.\n\n"
10581  << "This is the right vertex of the current shared "
10582  "boundary\n"
10583  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10584  << shd_bnd_right_vertex[1] << ")\n\n"
10585  << "This is the list of vertices on the destination "
10586  << "boundary\n";
10587  for (unsigned p = 0; p < nsub_poly; p++)
10588  {
10589  error << "Subpolyline #(" << p << ")\n";
10590  poly_to_connect_pt = tmp_vector_subpolylines[p];
10591  const unsigned n_v = poly_to_connect_pt->nvertex();
10592  for (unsigned i = 0; i < n_v; i++)
10593  {
10594  Vector<double> cvertex =
10595  poly_to_connect_pt->vertex_coordinate(i);
10596  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10597  << cvertex[1] << ")\n";
10598  }
10599  } // for (p < nsub_poly)
10600  throw OomphLibError(
10601  error.str(),
10602  "TriangleMesh::create_shared_polylines_connections()",
10603  OOMPH_EXCEPTION_LOCATION);
10604  } // if (!found_vertex_index)
10605 #endif
10606 
10607  // Create the connection, the right vertex of the current
10608  // shared boundary is connected with the vertex_index-th
10609  // vertex of sub_poly_to_connect-th subpolyline of the
10610  // destination boundary
10611  shd_poly_pt->connect_final_vertex_to_polyline(
10612  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10613 
10614  } // if (!connecting_to_an_overlaped_boundary)
10615  else
10616  {
10617  // We first look on the shared boundaries that overlap
10618  // the internal boundaries and the look for the
10619  // sub-polylines that are not marked as being overlaped
10620  // by shared boundaries
10621 
10622  // The vertex where to store the index to connect
10623  unsigned vertex_index = 0;
10624  // The subpoly number to connect
10625  unsigned sub_poly_to_connect = 0;
10626  // A flag to indicate if the connection was found
10627  bool found_vertex_index = false;
10628 
10629  // Get the shared boundaries id that are overlaping the
10630  // internal boundary
10631  Vector<unsigned> dst_shd_bnd_ids;
10632  get_shared_boundaries_overlapping_internal_boundary(
10633  uconnection_to_the_right, dst_shd_bnd_ids);
10634 
10635  // Get the number of shared polylines that were found to
10636  // overlap the internal boundary
10637  const unsigned n_shd_bnd_overlap_int_bnd =
10638  dst_shd_bnd_ids.size();
10639 
10640  // Loop over the shared boundaries that overlap the
10641  // internal boundary and look for the vertex to connect
10642  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10643  {
10644  // Get the shared polyline
10645  const unsigned new_connection_to_the_right =
10646  dst_shd_bnd_ids[ss];
10647 
10648  // Make sure that the destination polyline is not the
10649  // same as the current shared polyline
10650  if (bound_id != new_connection_to_the_right)
10651  {
10652  // Get the shared polyline that is overlaping the
10653  // internal boundary
10654  poly_to_connect_pt =
10655  boundary_polyline_pt(new_connection_to_the_right);
10656 
10657  if (poly_to_connect_pt != 0)
10658  {
10659  // Look for the vertex number in the destination
10660  // shared polyline
10661  found_vertex_index =
10662  get_connected_vertex_number_on_destination_polyline(
10663  poly_to_connect_pt,
10664  shd_bnd_right_vertex,
10665  vertex_index);
10666  } // if (poly_to_connect_pt != 0)
10667 
10668  // If we have found the vertex to connect then
10669  // break the loop
10670  if (found_vertex_index)
10671  {
10672  break;
10673  } // if (found_vertex_index)
10674 
10675  } // if (bound_id != new_connection_to_the_right)
10676 
10677  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10678 
10679  // If we have not yet found the vertex then look for it
10680  // in the sub-polylines that are not overlaped by shared
10681  // boundaries
10682  if (!found_vertex_index)
10683  {
10684  // Look for the vertex number to connect on each of
10685  // the subpolyines
10686  for (unsigned isub = 0; isub < nsub_poly; isub++)
10687  {
10688  // Only work with those sub-polylines that are not
10689  // overlaped by shared boundaries
10690  if (!boundary_marked_as_shared_boundary(
10691  uconnection_to_the_right, isub))
10692  {
10693  // Assign the pointer to the sub-polyline
10694  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10695  // Search for the vertex in the current sub-polyline
10696  found_vertex_index =
10697  get_connected_vertex_number_on_destination_polyline(
10698  poly_to_connect_pt,
10699  shd_bnd_right_vertex,
10700  vertex_index);
10701  // If we have found the vertex to connect then break the
10702  // loop
10703  if (found_vertex_index)
10704  {
10705  // But first save the subpoly number (chunk), that
10706  // will be used to perform the connection
10707  sub_poly_to_connect = isub;
10708  break;
10709  } // if (found_vertex_index)
10710 
10711  } // if (not overlaped by shared boundary)
10712 
10713  } // for (isub < nsub_poly)
10714 
10715  } // if (!found_vertex_index)
10716 
10717 #ifdef PARANOID
10718  // If we could not find the vertex index to connect then
10719  // we are in trouble
10720  if (!found_vertex_index)
10721  {
10722  std::stringstream error;
10723  error
10724  << "The current shared boundary (" << bound_id << ") was "
10725  << "marked to have a connection\nto the right with the "
10726  << "boundary (" << uconnection_to_the_right << ").\n"
10727  << "This last boundary is marked to be overlaped by "
10728  << "shared boundaries\n"
10729  << "The problem is that the right vertex of the current\n"
10730  << "shared boundary is not in the list of vertices of "
10731  << "the\nboundary to connect.\n\n"
10732  << "This is the right vertex of the current shared "
10733  << "boundary\n"
10734  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10735  << shd_bnd_right_vertex[1] << ")\n\n"
10736  << "This is the list of vertices on the destination "
10737  << "boundary (only those subpolylines not marked as "
10738  << "overlaped by\nshared boundaries)\n";
10739  for (unsigned p = 0; p < nsub_poly; p++)
10740  {
10741  if (!boundary_marked_as_shared_boundary(
10742  uconnection_to_the_right, p))
10743  {
10744  error << "Subpolyline #(" << p << ")\n";
10745  poly_to_connect_pt = tmp_vector_subpolylines[p];
10746  const unsigned n_v = poly_to_connect_pt->nvertex();
10747  for (unsigned i = 0; i < n_v; i++)
10748  {
10749  Vector<double> cvertex =
10750  poly_to_connect_pt->vertex_coordinate(i);
10751  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10752  << cvertex[1] << ")\n";
10753  }
10754  } // Not marked as overlaped
10755  } // for (p < nsub_poly)
10756  error << "\nThis is the list of vertices of the shared "
10757  << "polylines that overlap\nthe internal "
10758  << "boundary\n";
10759  Vector<unsigned> dst_shd_bnd_ids;
10760  get_shared_boundaries_overlapping_internal_boundary(
10761  uconnection_to_the_right, dst_shd_bnd_ids);
10762  const unsigned n_shd_bnd_overlap_int_bnd =
10763  dst_shd_bnd_ids.size();
10764  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10765  {
10766  const unsigned new_connection_to_the_right =
10767  dst_shd_bnd_ids[ss];
10768  poly_to_connect_pt =
10769  boundary_polyline_pt(new_connection_to_the_right);
10770  if (poly_to_connect_pt != 0)
10771  {
10772  const unsigned shd_bnd_id_overlap =
10773  poly_to_connect_pt->boundary_id();
10774  error << "Shared boundary id(" << shd_bnd_id_overlap
10775  << ")\n";
10776  const unsigned n_v = poly_to_connect_pt->nvertex();
10777  for (unsigned i = 0; i < n_v; i++)
10778  {
10779  Vector<double> cvertex =
10780  poly_to_connect_pt->vertex_coordinate(i);
10781  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10782  << cvertex[1] << ")\n";
10783  }
10784  } // if (poly_to_connect_pt != 0)
10785  } // for (ss < n_shd_bnd_overlap_int_bnd)
10786 
10787  throw OomphLibError(
10788  error.str(),
10789  "TriangleMesh::create_shared_polylines_connections()",
10790  OOMPH_EXCEPTION_LOCATION);
10791  } // if (!found_vertex_index)
10792 #endif
10793 
10794  // Create the connection, the left vertex of the current
10795  // shared boundary is connected with the vertex_index-th
10796  // vertex of sub_poly_to_connect-th subpolyline of the
10797  // destination boundary
10798  shd_poly_pt->connect_final_vertex_to_polyline(
10799  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10800 
10801  } // else if (!connecting_to_an_overlaped_boundary)
10802 
10803  } // else if (!connecting_to_an_split_boundary)
10804 
10805  } // if (connection_to_the_right != -1)
10806 
10807  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10808 
10809  } // for (ipoly < npoly)
10810 
10811  } // for (icurve < ncurves)
10812  }
10813 
10814  //=======================================================================
10815  // \short Compute the holes left by the halo elements, those adjacent
10816  // to the shared boundaries
10817  //=======================================================================
10818  template<class ELEMENT>
10820  Vector<Vector<double>>& output_holes_coordinates)
10821  {
10822  // Storage for number of processors and current processor
10823  const unsigned n_proc = this->communicator_pt()->nproc();
10824  const unsigned my_rank = this->communicator_pt()->my_rank();
10825 
10826  // Mark those done elements, so we do not repeat any coordinate left
10827  // by repeated halo elements
10828  std::map<FiniteElement*, bool> done_ele;
10829 
10830  // Loop over the processors and get the shared boundaries ids that
10831  // the current processor has with the other processors
10832  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10833  {
10834  // There are shared boundaries only with the other processors
10835  if (iproc != my_rank)
10836  {
10837  // Get the number of shared boundaries with the iproc
10838  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10839 
10840 #ifdef PARANOID
10841  // Get the number of shared boundaries with the iproc, but
10842  // reversing the indexes
10843  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10844  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10845  {
10846  std::ostringstream error_stream;
10847  error_stream
10848  << "The number of shared boundaries of processor (" << my_rank
10849  << ") with processor(" << iproc << "): (" << n_shd_bnd_iproc
10850  << ")\n"
10851  << "is different from the number of shared boundaries of "
10852  << "processor (" << iproc << ")\nwith processor (" << my_rank
10853  << "): (" << n_shd_bnd_iproc << ")\n\n";
10854  throw OomphLibError(error_stream.str(),
10855  OOMPH_CURRENT_FUNCTION,
10856  OOMPH_EXCEPTION_LOCATION);
10857 
10858  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10859 #endif
10860 
10861  // Loop over the shared boundaries ids
10862  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10863  {
10864  // Get the shared boundary id
10865  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10866 
10867  // Get the number of shared boundary elements
10868  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10869 
10870  // Loop over the shared boundary elements
10871  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10872  {
10873  // Get the shared boundary element
10874  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10875 
10876  // Only work with halo elements
10877  if (ele_pt->is_halo())
10878  {
10879  // If the element has not been visited
10880  if (!done_ele[ele_pt])
10881  {
10882  // Get the number of nodes
10883  const unsigned n_nodes = ele_pt->nnode();
10884 
10885  // Compute the centroid of the element
10886  Vector<double> element_centroid(2, 0.0);
10887  // Loop over the nodes
10888  for (unsigned k = 0; k < n_nodes; k++)
10889  {
10890  Node* tmp_node_pt = ele_pt->node_pt(k);
10891  // Loop over the dimension
10892  for (unsigned d = 0; d < 2; d++)
10893  {
10894  element_centroid[d] += tmp_node_pt->x(d);
10895  } // for (d < 2)
10896  } // for (k < n_nodes)
10897 
10898  // Average the data
10899  for (unsigned d = 0; d < 2; d++)
10900  {
10901  element_centroid[d] = element_centroid[d] / (double)n_nodes;
10902  } // for (d < 2)
10903 
10904  // Add the centroid to the output holes
10905  output_holes_coordinates.push_back(element_centroid);
10906 
10907  } // if (!done_ele[ele_pt])
10908 
10909  } // if (ele_pt->is_halo())
10910 
10911  } // for1 (e < n_shd_bnd_ele)
10912 
10913  } // for (i < n_shd_bnd_iproc)
10914 
10915  } // if (iproc != my_rank)
10916 
10917  } // for (iproc < n_proc)
10918  }
10919 
10920  //======================================================================
10921  // \short Keeps those vertices that define a hole, those that are
10922  // inside closed internal boundaries in the new polygons that define
10923  // the domain. Delete those outside/inside the outer polygons (this
10924  // is required since Triangle can not deal with vertices that define
10925  // holes outside the new outer polygons of the domain)
10926  //======================================================================
10927  template<class ELEMENT>
10929  Vector<TriangleMeshPolygon*>& polygons_pt,
10930  Vector<Vector<double>>& output_holes_coordinates)
10931  {
10932  // General strategy
10933 
10934  // 1) Identify the inner closed boundaries
10935 
10936  // 2) Separate the vertices in three groups
10937 
10938  // --- 2.1) The vertices inside the inner closed boundaries, these
10939  // are not deleted because they define holes
10940 
10941  // --- 2.2) The vertices outside the outer boundaries, these are
10942  // deleted only if they are outside the convex hull defined
10943  // by all the polygons
10944 
10945  // --- 2.3) Any other vertex is deleted
10946 
10947  // Get the number of input holes
10948  const unsigned n_input_holes = output_holes_coordinates.size();
10949 
10950  // Only do something if there are holes
10951  if (n_input_holes == 0)
10952  {
10953  return;
10954  }
10955 
10956  // Get the number of input polygons
10957  const unsigned n_polygons = polygons_pt.size();
10958 
10959  // Store the vertices of all the input polygons
10960  // vertices_polygons[x][ ][ ]: Polygon number
10961  // vertices_polygons[ ][x][ ]: Vertex number
10962  // vertices_polygons[ ][ ][x]: Vertex coordinate
10963  Vector<Vector<Vector<double>>> vertices_polygons(n_polygons);
10964 
10965  // Loop over all the polygons and get the vertices
10966  for (unsigned p = 0; p < n_polygons; p++)
10967  {
10968  // Get the number of polylines associated to the polygon
10969  const unsigned n_polylines = polygons_pt[p]->npolyline();
10970  // Loop over the polylines and get the vertices
10971  for (unsigned pp = 0; pp < n_polylines; pp++)
10972  {
10973  // Get the polyline
10974  const TriangleMeshPolyLine* tmp_poly_pt =
10975  polygons_pt[p]->polyline_pt(pp);
10976  // Get the number of vertices in the polyline
10977  const unsigned n_vertices = tmp_poly_pt->nvertex();
10978  // Loop over the vertices but only add (n_vertices-1) vertices,
10979  // the last vertex of polyline (pp) is the first vertex of
10980  // polyline (pp+1)
10981  for (unsigned v = 0; v < n_vertices - 1; v++)
10982  {
10983  // Get the current vertex
10984  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10985  vertices_polygons[p].push_back(current_vertex);
10986  } // for (v < nvertex)
10987  } // for (p < nouter_polylines)
10988  } // for (p < n_polygons)
10989 
10990  // -------------------------------------------------------------------
10991  // 1) Identify the inner closed boundaries
10992  // -------------------------------------------------------------------
10993 
10994  // A container that indicates if a given polygon should be
10995  // considered as an outer or as an inner polygon. By default all the
10996  // polygons are considered as outer polygons
10997  std::vector<bool> is_outer_polygon(n_polygons, true);
10998 
10999  // We only check for innner polygons if there are more than one
11000  // polygon
11001  if (n_polygons > 1)
11002  {
11003  // Propose an inner polygon, if one of the middle points of its
11004  // edges lies inside any other polygon then the proposed inner
11005  // polygon is marked as an internal polygon
11006 
11007  // Pre-compute the middle points of the edges in the polygons
11008  Vector<Vector<Vector<double>>> polygon_edge_middle_vertex(n_polygons);
11009 
11010  for (unsigned p = 0; p < n_polygons; p++)
11011  {
11012  // Temporary store the vertices of the proposed inner polygon
11013  Vector<Vector<double>> tmp_inner_polygon = vertices_polygons[p];
11014 
11015  // Get the number of vertices in the current proposed inner polygon
11016  const unsigned n_vertices = tmp_inner_polygon.size();
11017 
11018  // Resize with the number of edges in the polygon
11019  polygon_edge_middle_vertex[p].resize(n_vertices - 1);
11020 
11021  // Loop over the vertices and compute the middle point in the edge
11022  // that joins each pair of contiguous vertices
11023  for (unsigned e = 0; e < n_vertices - 1; e++)
11024  {
11025  // The dimension
11026  const unsigned dim = 2;
11027  polygon_edge_middle_vertex[p][e].resize(dim);
11028  for (unsigned d = 0; d < dim; d++)
11029  {
11030  polygon_edge_middle_vertex[p][e][d] =
11031  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e + 1][d]) / 2.0;
11032  } // for (d < 2)
11033 
11034  } // for (e < n_vertices - 1)
11035 
11036  } // for (p < n_polygons)
11037 
11038  // Loop over the polygons and for every loop propose a different
11039  // inner polygon
11040  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
11041  {
11042  // Flag to indicate that ONE of the middle edge vertices of the
11043  // proposed inner polygon is inside another polygon, this will
11044  // set the proposed inner polygon as an actual inner polygon
11045  bool is_inner_polygon = false;
11046 
11047  // Loop over all the polygons, except the proposed one and check
11048  // if all the middle edges of its edges are inside any other
11049  // polygon
11050  for (unsigned i = 0; i < n_polygons; i++)
11051  {
11052  // Do not check with the polygon itself
11053  if (i != idx_inner)
11054  {
11055  // Get the number of edges of the proposed inner polygon
11056  const unsigned n_edges =
11057  polygon_edge_middle_vertex[idx_inner].size();
11058  // Loop over the middle points in the edges of the current
11059  // proposed inner polygon
11060  for (unsigned e = 0; e < n_edges; e++)
11061  {
11062  // Get the vertex in the current proposed inner polygon
11063  Vector<double> current_vertex =
11064  polygon_edge_middle_vertex[idx_inner][e];
11065  // Check if the current vertex is inside the current i-th
11066  // polygon
11067  const bool is_point_inside = is_point_inside_polygon_helper(
11068  vertices_polygons[i], current_vertex);
11069 
11070  // If one point is inside then the polygon is inside the
11071  // i-th polygon
11072  if (is_point_inside)
11073  {
11074  // The polygon is an inner polygon
11075  is_inner_polygon = true;
11076  // Break the loop
11077  break;
11078  } // if (is_point_inside)
11079 
11080  } // for (e < n_edges)
11081 
11082  } // if (i != idx_inner)
11083 
11084  // Are all the vertices of the current proposed inner polygon
11085  // inside the i-th polygon
11086  if (is_inner_polygon)
11087  {
11088  // The current proposed inner polygon is an actual inner
11089  // polygon, and is inside the i-th polygon
11090  break;
11091  }
11092 
11093  } // for (i < n_polygons)
11094 
11095  // Is the current proposed inner polygon an actual inner polygon
11096  if (is_inner_polygon)
11097  {
11098  // The current proposed inner polygon is a real inner polygon
11099  is_outer_polygon[idx_inner] = false;
11100  }
11101  else
11102  {
11103  // The current proposed inner polygon IS NOT a real inner
11104  // polygon
11105  is_outer_polygon[idx_inner] = true;
11106  }
11107 
11108  } // for (idx_outer < npolygons)
11109 
11110  } // if (n_polygons > 1)
11111 
11112  // Count the number of outer closed boundaries and inner closed
11113  // boundaries
11114  unsigned n_outer_polygons = 0;
11115  unsigned n_inner_polygons = 0;
11116  // Also get the indexes of the inner polygons
11117  Vector<unsigned> index_inner_polygon;
11118  // Loop over the polygons
11119  for (unsigned i = 0; i < n_polygons; i++)
11120  {
11121  if (is_outer_polygon[i])
11122  {
11123  // Increase the counter for outer polygons
11124  n_outer_polygons++;
11125  }
11126  else
11127  {
11128  // Increase the counter for inner polygons
11129  n_inner_polygons++;
11130  // Store the index of the inner polygon
11131  index_inner_polygon.push_back(i);
11132  }
11133  } // for (i < n_polygons)
11134 
11135  // -------------------------------------------------------------------
11136  // 2) Separate the vertices in three groups
11137 
11138  // --- 2.1) The vertices inside the inner closed boundaries, these are
11139  // not deleted because they define holes
11140 
11141  // --- 2.2) The vertices outside the outer boundaries, these are
11142  // deleted only if they are outside the convex hull defined
11143  // by all the polygons
11144 
11145  // --- 2.3) Any other vertex is deleted
11146  // -------------------------------------------------------------------
11147 
11148  // Keep track of the vertices inside the inner closed boundaries (by
11149  // default all vertices not inside the inner polygons)
11150  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11151 
11152  // Keep track of the vertices outside the outer closed boundaries
11153  // (by default all the vertices are outside the outer polygons)
11154  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11155 
11156  // Keep track of the vertices inside the convex hull (by default
11157  // all the vertices are not inside the convex hull)
11158  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11159 
11160  // Mark the vertices inside the inner closed boundaries
11161  Vector<Vector<Vector<double>>> vertex_inside_inner_polygon(
11162  n_inner_polygons);
11163 
11164  // -------------------------------------------------------------------
11165  // Loop over the inner polygons and find all the vertices inside
11166  // each one
11167  for (unsigned i = 0; i < n_inner_polygons; i++)
11168  {
11169  // Get the vertex of the inner polygon
11170  const unsigned ii = index_inner_polygon[i];
11171  // Loop over the vertices defining holes, mark and store those
11172  // inside the inner polygon
11173  for (unsigned h = 0; h < n_input_holes; h++)
11174  {
11175  // Check if the vertex has not been already marked as inside
11176  // another polygon
11177  if (!is_inside_an_inner_polygon[h])
11178  {
11179  // Check if the hole is inside the current inner polygon
11180  const bool is_inside_polygon = is_point_inside_polygon_helper(
11181  vertices_polygons[ii], output_holes_coordinates[h]);
11182 
11183  // If the vertex is inside the current inner polygon then mark
11184  // it and associate the vertices to the current inner polygon
11185  if (is_inside_polygon)
11186  {
11187  // Set as inside an inner polygon
11188  is_inside_an_inner_polygon[h] = true;
11189  // Associate the vertex to the current inner polygon
11190  vertex_inside_inner_polygon[i].push_back(
11191  output_holes_coordinates[h]);
11192  } // if (is_inside_polygon)
11193 
11194  } // if (!is_inside_an_inner_polygon[h])
11195 
11196  } // for (h < n_input_holes)
11197 
11198  } // for (i < n_polygons)
11199 
11200  // -------------------------------------------------------------------
11201  // Loop over the vertices defining holes and mark those as outside the
11202  // outer polygons
11203  for (unsigned h = 0; h < n_input_holes; h++)
11204  {
11205  // Check if the vertex has not been already marked as inside
11206  // another polygon
11207  if (!is_inside_an_inner_polygon[h])
11208  {
11209  // Loop over the polygons and check if the vertex is outside ALL
11210  // the outer polygons
11211  for (unsigned i = 0; i < n_polygons; i++)
11212  {
11213  // Only work with outer polygons
11214  if (is_outer_polygon[i])
11215  {
11216  // Check if the hole is inside the current outer polygon
11217  const bool is_inside_polygon = is_point_inside_polygon_helper(
11218  vertices_polygons[i], output_holes_coordinates[h]);
11219 
11220  // If the vertex is inside the current outer polygon then
11221  // mark it and break the loop (it is not outside ALL the
11222  // polygons)
11223  if (is_inside_polygon)
11224  {
11225  // Set as inside an outer polygon
11226  is_outside_the_outer_polygons[h] = false;
11227  // Break the loop
11228  break;
11229  } // if (is_inside_polygon)
11230 
11231  } // if (is_outer_polygon[i])
11232 
11233  } // for (i < n_polygons)
11234 
11235  } // if (!is_inside_an_inner_polygon[h])
11236  else
11237  {
11238  // If the vertex is inside an inner polygon then it is inside an
11239  // outer polygon
11240  is_outside_the_outer_polygons[h] = false;
11241  } // else if (!is_inside_an_inner_polygon[h])
11242 
11243  } // for (h < n_input_holes)
11244 
11245  // -------------------------------------------------------------------
11246  // Compute the convex hull Create the data structure
11247  std::vector<Point> input_vertices_convex_hull;
11248  // Copy ALL the vertices of the polygons
11249  // Loop over the polygons
11250  for (unsigned p = 0; p < n_polygons; p++)
11251  {
11252  // Get the number of vertices
11253  const unsigned n_vertices = vertices_polygons[p].size();
11254  // Loop over the vertices in the polygon
11255  for (unsigned v = 0; v < n_vertices; v++)
11256  {
11257  // Create a new "Point" to store in the input vertices
11258  Point point;
11259  // Assign the values to the "Point"
11260  point.x = vertices_polygons[p][v][0];
11261  point.y = vertices_polygons[p][v][1];
11262  // Add the "Point" to the input vertices
11263  input_vertices_convex_hull.push_back(point);
11264  } // for (v < n_vertices)
11265  } // for (p < n_polygons)
11266 
11267  // Compute the convex hull
11268  std::vector<Point> output_vertices_convex_hull =
11269  convex_hull(input_vertices_convex_hull);
11270 
11271  // Get the number of vertices in the convex hull
11272  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11273 
11274  // Copy the output to the used data structures
11275  Vector<Vector<double>> vertices_convex_hull(n_vertices_convex_hull);
11276  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11277  {
11278  // Resize the data structure
11279  vertices_convex_hull[i].resize(2);
11280  // Copy the data
11281  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11282  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11283  } // for (i < n_vertices_convex_hull)
11284 
11285  // Loop over the vertices defining holes, work only with those
11286  // outside ALL the outer boundaries and mark those inside the convex
11287  // hull
11288  for (unsigned h = 0; h < n_input_holes; h++)
11289  {
11290  // Only work with those outside ALL the outer polygons
11291  if (is_outside_the_outer_polygons[h])
11292  {
11293  // Check if the hole is inside the convex hull
11294  const bool is_inside_convex_hull = is_point_inside_polygon_helper(
11295  vertices_convex_hull, output_holes_coordinates[h]);
11296 
11297  // If the vertex is inside the convex hull then mark it
11298  if (is_inside_convex_hull)
11299  {
11300  // Set as inside the convex hull
11301  is_inside_the_convex_hull[h] = true;
11302  } // if (is_inside_convex_hull)
11303 
11304  } // if (is_outside_the_outer_polygons[h])
11305  else
11306  {
11307  // Any vertex inside any outer polygon is inside the convex hull
11308  is_inside_the_convex_hull[h] = true;
11309  } // else if (is_outside_the_outer_polygons[h])
11310 
11311  } // for (h < n_input_holes)
11312 
11313  // Store the output holes, only (those inside an inner polygon) OR
11314  // (those outside ALL the polygons AND inside the convex hull)
11315  Vector<Vector<double>> hole_kept;
11316  for (unsigned h = 0; h < n_input_holes; h++)
11317  {
11318  // Check if the hole should be kept
11319  if ((is_inside_an_inner_polygon[h]) ||
11320  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11321  {
11322  // Copy the hole information
11323  hole_kept.push_back(output_holes_coordinates[h]);
11324  } // if (keep_hole[h])
11325  } // for (h < n_input_holes)
11326 
11327  // Clear the previous storage
11328  output_holes_coordinates.clear();
11329  // Set the output holes
11330  output_holes_coordinates = hole_kept;
11331  }
11332 
11333  //======================================================================
11334  // \short Sorts the polylines so they be contiguous and then we can
11335  // create a closed or open curve from them
11336  //======================================================================
11337  template<class ELEMENT>
11339  Vector<TriangleMeshPolyLine*>& unsorted_polylines_pt,
11340  Vector<Vector<TriangleMeshPolyLine*>>& sorted_polylines_pt)
11341  {
11342  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11343  unsigned n_sorted_polylines = 0;
11344  unsigned curves_index = 0;
11345 
11346  // Map to know which polyline has been already sorted
11347  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11348 
11349  do
11350  {
11351  // Create the list that stores the polylines and allows to introduce
11352  // polylines to the left and to the right
11353  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11354  bool changes = false;
11355 
11356  // Create pointers to the left and right "side" of the sorted list of
11357  // new created TriangleMeshPolyLines
11358  TriangleMeshPolyLine* left_pt = 0;
11359  TriangleMeshPolyLine* right_pt = 0;
11360 
11361  // 1) Take the first non done polyline on the unsorted list of polylines
11362  unsigned pp = 0;
11363  bool found_root_polyline = false;
11364  while (pp < n_unsorted_polylines && !found_root_polyline)
11365  {
11366  if (!done_polyline[unsorted_polylines_pt[pp]])
11367  {
11368  found_root_polyline = true;
11369  }
11370  else
11371  {
11372  pp++;
11373  }
11374  }
11375 
11376  // Check if there are polylines to be sorted
11377  if (pp < n_unsorted_polylines)
11378  {
11379  // 2) Mark the polyline as done
11380  left_pt = right_pt = unsorted_polylines_pt[pp];
11381  done_polyline[left_pt] = true;
11382  // Increment the number of sorted polylines
11383  n_sorted_polylines++;
11384 
11385  // 3) Add this polyline to the sorted list and use it as root
11386  // to sort the other polylines
11387  sorted_polyline_list_pt.push_back(left_pt);
11388 
11389  do
11390  {
11391  changes = false;
11392 
11393  Vector<double> left_vertex(2);
11394  Vector<double> right_vertex(2);
11395 
11396  left_pt->initial_vertex_coordinate(left_vertex);
11397  right_pt->final_vertex_coordinate(right_vertex);
11398 
11399  for (unsigned i = pp + 1; i < n_unsorted_polylines; i++)
11400  {
11401  TriangleMeshPolyLine* current_polyline_pt =
11402  unsorted_polylines_pt[i];
11403  if (!done_polyline[current_polyline_pt])
11404  {
11405  Vector<double> initial_vertex(2);
11406  Vector<double> final_vertex(2);
11407  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11408  current_polyline_pt->final_vertex_coordinate(final_vertex);
11409 
11410  // Compare if the current polyline should go to the left or
11411  // to the right on the sorted polyline list
11412 
11413  // Go to the left
11414  if (left_vertex == final_vertex)
11415  {
11416  left_pt = current_polyline_pt;
11417  sorted_polyline_list_pt.push_front(left_pt);
11418  done_polyline[left_pt] = true;
11419  n_sorted_polylines++;
11420 
11421  // We have added one more polyline, go for another round
11422  changes = true;
11423  }
11424  // Go to the right
11425  else if (right_vertex == initial_vertex)
11426  {
11427  right_pt = current_polyline_pt;
11428  sorted_polyline_list_pt.push_back(right_pt);
11429  done_polyline[right_pt] = true;
11430  n_sorted_polylines++;
11431 
11432  // We have added one more polyline, go for another round
11433  changes = true;
11434  }
11435  // Go to the left but it is reversed
11436  else if (left_vertex == initial_vertex)
11437  {
11438  current_polyline_pt->reverse();
11439  left_pt = current_polyline_pt;
11440  sorted_polyline_list_pt.push_front(left_pt);
11441  done_polyline[left_pt] = true;
11442  n_sorted_polylines++;
11443 
11444  // We have added one more polyline, go for another round
11445  changes = true;
11446  }
11447  // Go to the right but it is reversed
11448  else if (right_vertex == final_vertex)
11449  {
11450  current_polyline_pt->reverse();
11451  right_pt = current_polyline_pt;
11452  sorted_polyline_list_pt.push_back(right_pt);
11453  done_polyline[right_pt] = true;
11454  n_sorted_polylines++;
11455 
11456  // We have added one more polyline, go for another round
11457  changes = true;
11458  }
11459  } // if (!done_polyline[current_polyline_pt])
11460  if (changes)
11461  {
11462  break;
11463  }
11464  } // for (i < n_unsorted_polylines)
11465  } while (changes);
11466 
11467  } // if (pp < n_unsorted_polylines)
11468  else
11469  {
11470  // All the polylines are now on the sorted list of polylines
11471 #ifdef PARANOID
11472  // This case comes when it was not possible to find a root polyline
11473  // since all of them are marked as done but the number of sorted and
11474  // unsorted polylines is not the same
11475  if (!found_root_polyline)
11476  {
11477  std::stringstream err;
11478  err << "It was not possible to find a root polyline to sort the "
11479  << "others around it.\nThe number of unsorted and sorted "
11480  << "polylines is different, it means that\nnot all the "
11481  << "polylines have been sorted.\n"
11482  << "Found root polyline: (" << found_root_polyline << ")\n"
11483  << "Sorted polylines: (" << n_sorted_polylines << ")\n"
11484  << "Unsorted polylines: (" << n_unsorted_polylines << ")\n";
11485  throw OomphLibError(err.str(),
11486  "TriangleMesh::sort_polylines_helper()",
11487  OOMPH_EXCEPTION_LOCATION);
11488  }
11489 #endif
11490  }
11491 
11492  // Create the storage for the new sorted polylines and copy them on the
11493  // vector structure for sorted polylines
11494  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11495 
11496  // Create the temporal vector that stores the sorted polylines
11497  Vector<TriangleMeshPolyLine*> tmp_sorted_polylines(
11498  n_sorted_polyline_on_list);
11499  unsigned counter = 0;
11500 
11501  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11502  for (it_polyline = sorted_polyline_list_pt.begin();
11503  it_polyline != sorted_polyline_list_pt.end();
11504  it_polyline++)
11505  {
11506  tmp_sorted_polylines[counter] = *it_polyline;
11507  counter++;
11508  }
11509 
11510  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11511 
11512  ++curves_index;
11513 
11514  } while (n_sorted_polylines < n_unsorted_polylines);
11515 
11516 #ifdef PARANOID
11517  // Verify that the number of polylines on the sorted list is the same
11518  // as the number of polylines on the unsorted list
11519  if (n_sorted_polylines != n_unsorted_polylines)
11520  {
11521  std::stringstream err;
11522  err << "The number of polylines on the unsorted and sorted vectors"
11523  << " is different,\n"
11524  << "it means that not all the polylines have been sorted.\n"
11525  << "Sorted polylines: " << n_sorted_polylines
11526  << "\nUnsorted polylines: " << n_unsorted_polylines;
11527  throw OomphLibError(err.str(),
11528  "TriangleMesh::sort_polylines_helper()",
11529  OOMPH_EXCEPTION_LOCATION);
11530  }
11531 #endif
11532  }
11533 
11534  //======================================================================
11535  // \short Creates the shared boundaries
11536  //======================================================================
11537  template<class ELEMENT>
11539  OomphCommunicator* comm_pt,
11540  const Vector<unsigned>& element_domain,
11541  const Vector<GeneralisedElement*>& backed_up_el_pt,
11542  const Vector<FiniteElement*>& backed_up_f_el_pt,
11543  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
11544  const bool& overrule_keep_as_halo_element_status)
11545  {
11546  // Storage for number of processors and current processor
11547  const unsigned nproc = comm_pt->nproc();
11548  const unsigned my_rank = comm_pt->my_rank();
11549 
11550  // Storage for all the halo elements on all processors
11551  // halo_element[iproc][jproc][ele_number]
11552  // Stores the "ele_number"-th halo element of processor "iproc" with
11553  // processor "jproc"
11554  Vector<Vector<Vector<GeneralisedElement*>>> halo_element_pt(nproc);
11555  // Create complete storage for the halo_element_pt container
11556  for (unsigned iproc = 0; iproc < nproc; iproc++)
11557  {
11558  halo_element_pt[iproc].resize(nproc);
11559  }
11560 
11561  // Store the global index of the element, used to check for possible
11562  // misclassification of halo elements in the above container
11563  // (halo_element_pt)
11564  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11565 
11566  // Get the halo elements on all processors
11567  this->get_halo_elements_on_all_procs(nproc,
11568  element_domain,
11569  backed_up_el_pt,
11570  processors_associated_with_data,
11571  overrule_keep_as_halo_element_status,
11572  element_to_global_index,
11573  halo_element_pt);
11574 
11575  // Resize the shared polylines container
11576  flush_shared_boundary_polyline_pt();
11577  Shared_boundary_polyline_pt.resize(nproc);
11578 
11579  // Create a set that store only the elements that will be kept in
11580  // the processor as nonhalo element, those whose element_domains is
11581  // equal to my_rank. This set is used when creating the shared
11582  // polylines and identify the connections to the original boundaries
11583  std::set<FiniteElement*> element_in_processor_pt;
11584  const unsigned n_ele = backed_up_f_el_pt.size();
11585  for (unsigned e = 0; e < n_ele; e++)
11586  {
11587  if (element_domain[e] == my_rank)
11588  {
11589  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11590  } // if (element_domain[e] == my_rank)
11591  } // for (e < n_elex)
11592 
11593  // Look for elements edges that may lie on internal boundaries
11594  // If that is the case then relate the face with the boundary on
11595  // which it lies
11596  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
11597  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11598 
11599  // Now we have all the halo elements on all processors. Use the
11600  // edges shared by the halo elements to create the shared boundaries.
11601  this->create_polylines_from_halo_elements_helper(
11602  element_domain,
11603  element_to_global_index,
11604  element_in_processor_pt,
11605  halo_element_pt,
11606  elements_edges_on_boundary,
11607  Shared_boundary_polyline_pt);
11608  }
11609 
11610  //======================================================================
11611  /// \short Creates the halo elements on all processors
11612  /// Gets the halo elements on all processors, these elements are then used
11613  /// on the function that computes the shared boundaries among the processors
11614  //======================================================================
11615  template<class ELEMENT>
11617  const unsigned& nproc,
11618  const Vector<unsigned>& element_domain,
11619  const Vector<GeneralisedElement*>& backed_up_el_pt,
11620  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
11621  const bool& overrule_keep_as_halo_element_status,
11622  std::map<GeneralisedElement*, unsigned>& element_to_global_index,
11623  Vector<Vector<Vector<GeneralisedElement*>>>& output_halo_elements_pt)
11624  {
11625  const unsigned n_ele = backed_up_el_pt.size();
11626 
11627  // Loop over all the processors
11628  for (unsigned iproc = 0; iproc < nproc; iproc++)
11629  {
11630  // Boolean to know which elements has been already added to the
11631  // halo scheme on "iproc" processor
11632  Vector<std::map<GeneralisedElement*, bool>> already_added(nproc);
11633 
11634  // Loop over all backed up elements
11635  for (unsigned e = 0; e < n_ele; e++)
11636  {
11637  // Get element and its domain
11638  GeneralisedElement* el_pt = backed_up_el_pt[e];
11639  unsigned el_domain = element_domain[e];
11640 
11641  // If element is NOT located on "iproc" processor then check if it is
11642  // halo with "el_domain" processor
11643  if (el_domain != iproc)
11644  {
11645  // If this current mesh has been told to keep all elements as halos,
11646  // OR the element itself knows that it must be kept then
11647  // keep it
11648  if ((this->Keep_all_elements_as_halos) ||
11649  (el_pt->must_be_kept_as_halo()))
11650  {
11651  if (!overrule_keep_as_halo_element_status)
11652  {
11653  // Add as halo element whose non-halo counterpart is
11654  // located on processor "el_domain"
11655  if (!already_added[el_domain][el_pt])
11656  {
11657  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11658  already_added[el_domain][el_pt] = true;
11659  element_to_global_index[el_pt] = e;
11660  }
11661  }
11662  }
11663  // Otherwise: Is one of the nodes associated with other processor?
11664  else
11665  {
11666  // Can only have nodes if this is a finite element
11667  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11668  if (finite_el_pt != 0)
11669  {
11670  unsigned n_node = finite_el_pt->nnode();
11671  for (unsigned n = 0; n < n_node; n++)
11672  {
11673  Node* nod_pt = finite_el_pt->node_pt(n);
11674 
11675  // Keep element?
11676  std::set<unsigned>::iterator it =
11677  processors_associated_with_data[nod_pt].find(iproc);
11678  if (it != processors_associated_with_data[nod_pt].end())
11679  {
11680  // Add as root halo element whose non-halo counterpart is
11681  // located on processor "el_domain"
11682  if (!already_added[el_domain][el_pt])
11683  {
11684  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11685  already_added[el_domain][el_pt] = true;
11686  element_to_global_index[el_pt] = e;
11687  }
11688  // Now break out of loop over nodes
11689  break;
11690  } // if (it!=processors_associated_with_data[nod_pt].end())
11691  } // for (n < n_node)
11692  } // if (finite_el_pt!=0)
11693  } // else (this->Keep_all_elements_as_halos)
11694  } // if (el_domain!=iproc)
11695  } // for (e < nele)
11696  } // for (iproc < nproc)
11697  }
11698 
11699  //====================================================================
11700  // \short Get the element edges (pair of nodes, edges) that lie
11701  // on a boundary (used to mark shared boundaries that lie on
11702  // internal boundaries)
11703  //====================================================================
11704  template<class ELEMENT>
11706  std::map<std::pair<Node*, Node*>, unsigned>& element_edges_on_boundary)
11707  {
11708  // The number of original boundaries
11709  const unsigned nbound = this->nboundary();
11710  // Loop over the boundaries
11711  for (unsigned b = 0; b < nbound; b++)
11712  {
11713  // Keep track of the pair of nodes done
11714  std::map<std::pair<Node*, Node*>, bool> edge_done;
11715  // Get the number of elements on the boundary
11716  const unsigned nbound_ele = this->nboundary_element(b);
11717  for (unsigned e = 0; e < nbound_ele; e++)
11718  {
11719  // Get the boundary bulk element
11720  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11721  // Get the face index
11722  int face_index = this->face_index_at_boundary(b, e);
11723  // Create the face element
11724  FiniteElement* face_ele_pt =
11725  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
11726  // Get the number of nodes on the face element
11727  const unsigned nnodes = face_ele_pt->nnode();
11728  // Get the first and last node
11729  Node* first_node_pt = face_ele_pt->node_pt(0);
11730  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
11731 
11732  // Create the pair to store the nodes
11733  std::pair<Node*, Node*> edge =
11734  std::make_pair(first_node_pt, last_node_pt);
11735 
11736  // Has the edge been included
11737  if (!edge_done[edge])
11738  {
11739  // Mark the edge as done
11740  edge_done[edge] = true;
11741 
11742  // Create the reversed version and mark it as done too
11743  std::pair<Node*, Node*> inv_edge =
11744  std::make_pair(last_node_pt, first_node_pt);
11745 
11746  // Mark the reversed edge as done
11747  edge_done[inv_edge] = true;
11748 
11749  // Mark the edge to belong to boundary b
11750  element_edges_on_boundary[edge] = b;
11751  } // if (!edge_done[edge])
11752 
11753  // Free the memory allocated for the face element
11754  delete face_ele_pt;
11755  face_ele_pt = 0;
11756 
11757  } // for (e < nbound_ele)
11758 
11759  } // for (b < nbound)
11760  }
11761 
11762  // ======================================================================
11763  // \short Creates polylines from the intersection of halo elements on
11764  // all processors. The new polylines define the shared boundaries in
11765  // the domain This method computes the polylines on ALL processors,
11766  // that is why the three dimensions in the structure
11767  // output_polylines_pt[iproc][ncurve][npolyline]
11768  // ======================================================================
11769  template<class ELEMENT>
11771  const Vector<unsigned>& element_domain,
11772  std::map<GeneralisedElement*, unsigned>& element_to_global_index,
11773  std::set<FiniteElement*>& element_in_processor_pt,
11774  Vector<Vector<Vector<GeneralisedElement*>>>& input_halo_elements,
11775  std::map<std::pair<Node*, Node*>, unsigned>& elements_edges_on_boundary,
11776  Vector<Vector<Vector<TriangleMeshPolyLine*>>>& output_polylines_pt)
11777  {
11778  const unsigned nproc = this->communicator_pt()->nproc();
11779  const unsigned my_rank = this->communicator_pt()->my_rank();
11780 
11781  // ---------------------------------------------------------------
11782  // Get the edges shared between each pair of processors
11783  // ---------------------------------------------------------------
11784 
11785  // Storage for the edges (pair of nodes) shared between a pair of
11786  // processors
11787  Vector<Vector<Vector<std::pair<Node*, Node*>>>> edges(nproc);
11788 
11789  // Each edge is associated to two elements, a haloi (halo element
11790  // in processors i) and a haloj (halo element in processors j)
11791  Vector<Vector<Vector<Vector<FiniteElement*>>>> edge_element_pt(nproc);
11792 
11793  // Each edge is associated to two elements, a haloi and a haloj,
11794  // the edge was created from a given face from each element, the
11795  // haloi face is stored at [0], the haloj face is stored at [1]
11796  Vector<Vector<Vector<Vector<int>>>> edge_element_face(nproc);
11797 
11798  // Store the possible internal boundary id associated to each edge
11799  // (-1 if there is no association). Some edges may overlap an
11800  // internal boundary (and only internal boundaries)
11801  Vector<Vector<Vector<int>>> edge_boundary(nproc);
11802 
11803  // Mark those edges (pair of nodes overlapped by a shared boundary)
11804  std::map<std::pair<Node*, Node*>, bool> overlapped_edge;
11805 
11806  // Resize the containers, they store info. for each pair of
11807  // processors
11808 
11809  // First resize the global container
11810  Shared_boundaries_ids.resize(nproc);
11811  for (unsigned j = 0; j < nproc; j++)
11812  {
11813  edges[j].resize(nproc);
11814  edge_element_pt[j].resize(nproc);
11815  edge_element_face[j].resize(nproc);
11816  edge_boundary[j].resize(nproc);
11817 
11818  // Resize the global container for shared boundaries ids
11819  Shared_boundaries_ids[j].resize(nproc);
11820 
11821  } // for (j < nproc)
11822 
11823  // Take the halo elements of processor "iproc" and compare their
11824  // edges with halo elements of other processors (except itself)
11825  for (unsigned iproc = 0; iproc < nproc; iproc++)
11826  {
11827  // Take the halo elements of processor iproc and compare with
11828  // other processors
11829  // Start from the iproc + 1,
11830  // 1) To avoid comparing with itself,
11831  // 2) To avoid generation of repeated boundaries
11832  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11833  {
11834  // **************************************************************
11835  // FIRST PART
11836  // 1) Get the halo elements of processor "iproc" with processor
11837  // "jproc"
11838  // 2) Get the halo elements of processor "jproc" with processor
11839  // "iproc"
11840  // 3) Compare their edges and those that match are the ones that
11841  // define the shared boundaries
11842  // **************************************************************
11843 
11844  // Storage for halo elements
11845  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11846  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11847 
11848  // Get the halo elements of "iproc" with "jproc"
11849  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11850 
11851  // If there are halo elements then there are shared boundaries
11852  const unsigned nhalo_elements_iproc_with_jproc =
11853  halo_elements_iproc_with_jproc.size();
11854  // DEBP(nhalo_elements_iproc_with_jproc);
11855  if (nhalo_elements_iproc_with_jproc > 0)
11856  {
11857  // Get the halo elements of "jproc" with "iproc"
11858  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11859 
11860  // If there are halo elements then there are shared
11861  // boundaries
11862  const unsigned nhalo_elements_jproc_with_iproc =
11863  halo_elements_jproc_with_iproc.size();
11864 // DEBP(nhalo_elements_jproc_with_iproc);
11865 #ifdef PARANOID
11866  if (nhalo_elements_jproc_with_iproc == 0)
11867  {
11868  // If there are halo elements of iproc with jproc there
11869  // MUST be halo elements on the other way round, not
11870  // necessary the same but at least one
11871  std::stringstream err;
11872  err << "There are no halo elements from processor (" << jproc
11873  << ") "
11874  << "with processor (" << iproc << ").\n"
11875  << "This is strange since there are halo elements from "
11876  << "processor (" << iproc << ") with processor (" << jproc
11877  << ").\n"
11878  << "Number of halo elements from (" << iproc << ") to ("
11879  << jproc << ") : (" << nhalo_elements_iproc_with_jproc << ")\n"
11880  << "Number of halo elements from (" << jproc << ") to ("
11881  << iproc << ") : (" << nhalo_elements_jproc_with_iproc << ")\n";
11882  throw OomphLibError(
11883  err.str(),
11884  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11885  OOMPH_EXCEPTION_LOCATION);
11886  }
11887 #endif
11888  // The edges are defined as pair of nodes
11889  Vector<Node*> halo_edges_iproc;
11890  unsigned halo_edges_counter_iproc = 0;
11891  Vector<Node*> halo_edges_jproc;
11892  unsigned halo_edges_counter_jproc = 0;
11893 
11894  // Map to associate the edge with the element used to create it
11895  std::map<std::pair<Node*, Node*>, FiniteElement*>
11896  edgesi_to_element_pt;
11897 
11898  // Map to associated the edge with the face number of the
11899  // element that created it
11900  std::map<std::pair<std::pair<Node*, Node*>, FiniteElement*>, int>
11901  edgesi_element_pt_to_face_index;
11902 
11903  // Map to associate the edge with the element used to create it
11904  std::map<std::pair<Node*, Node*>, FiniteElement*>
11905  edgesj_to_element_pt;
11906 
11907  // Map to associated the edge with the face number of the
11908  // element that created it
11909  std::map<std::pair<std::pair<Node*, Node*>, FiniteElement*>, int>
11910  edgesj_element_pt_to_face_index;
11911 
11912  // **************************************************************
11913  // 1.1) Store the edges of the "iproc" halo elements
11914  // **************************************************************
11915  // Go throught halo elements on "iproc" processor
11916  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11917  {
11918 #ifdef PARANOID
11919  unsigned e =
11920  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11921  // Only work with halo elements inside the "jproc" processor
11922  if (element_domain[e] != jproc)
11923  {
11924  // There was a problem on the ihalo-jhalo classification
11925  std::stringstream err;
11926  err << "There was a problem on the ihalo-jhalo classification.\n"
11927  << "One of the elements, (the one with the (" << e << ")-th "
11928  << "index ) is not on the (" << jproc << ")-th processor\n"
11929  << "but it was stored as a halo element of processor ("
11930  << iproc << ") with processor (" << jproc << ").\n";
11931  throw OomphLibError(
11932  err.str(),
11933  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11934  OOMPH_EXCEPTION_LOCATION);
11935  }
11936 #endif
11937 
11938  FiniteElement* el_pt =
11939  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11940 
11941  if (el_pt == 0)
11942  {
11943  std::stringstream err;
11944  err << "The halo element (" << ih
11945  << ") could not be casted to the "
11946  << "FiniteElement type.\n";
11947  throw OomphLibError(
11948  err.str(),
11949  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11950  OOMPH_EXCEPTION_LOCATION);
11951  }
11952 
11953 #ifdef PARANOID
11954  // Number of nodes on this element
11955  const unsigned n_nodes = el_pt->nnode();
11956 
11957  // The number of nodes on every element should be at least
11958  // three since we are going to work with the cornes nodes,
11959  // the ones with index 0, 1 and 2
11960  if (n_nodes < 3)
11961  {
11962  std::stringstream err;
11963  err << "The number of nodes of the " << ih
11964  << "-th halo element is"
11965  << " (" << n_nodes << ").\nWe can not work with triangle "
11966  << "elements with less than three nodes\n";
11967  throw OomphLibError(
11968  err.str(),
11969  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11970  OOMPH_EXCEPTION_LOCATION);
11971  }
11972 #endif
11973 
11974  // Get the corner nodes, the first three nodes
11975  Node* first_node_pt = el_pt->node_pt(0);
11976  Node* second_node_pt = el_pt->node_pt(1);
11977  Node* third_node_pt = el_pt->node_pt(2);
11978 
11979  // Store the edges
11980  halo_edges_iproc.push_back(first_node_pt);
11981  halo_edges_iproc.push_back(second_node_pt);
11982  halo_edges_counter_jproc++;
11983 
11984  halo_edges_iproc.push_back(second_node_pt);
11985  halo_edges_iproc.push_back(third_node_pt);
11986  halo_edges_counter_jproc++;
11987 
11988  halo_edges_iproc.push_back(third_node_pt);
11989  halo_edges_iproc.push_back(first_node_pt);
11990  halo_edges_counter_jproc++;
11991 
11992  // Store the info. of the element used to create these edges
11993  std::pair<Node*, Node*> edge1 =
11994  std::make_pair(first_node_pt, second_node_pt);
11995  edgesi_to_element_pt[edge1] = el_pt;
11996 
11997  std::pair<Node*, Node*> edge2 =
11998  std::make_pair(second_node_pt, third_node_pt);
11999  edgesi_to_element_pt[edge2] = el_pt;
12000 
12001  std::pair<Node*, Node*> edge3 =
12002  std::make_pair(third_node_pt, first_node_pt);
12003  edgesi_to_element_pt[edge3] = el_pt;
12004 
12005  // Store the face index of the edge in the element
12006  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
12007  std::make_pair(edge1, el_pt);
12008  edgesi_element_pt_to_face_index[edge_ele1] = 2;
12009 
12010  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
12011  std::make_pair(edge2, el_pt);
12012  edgesi_element_pt_to_face_index[edge_ele2] = 0;
12013 
12014  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
12015  std::make_pair(edge3, el_pt);
12016  edgesi_element_pt_to_face_index[edge_ele3] = 1;
12017 
12018  } // for (ih < nhalo_elements_iproc_with_jproc)
12019 
12020  // **************************************************************
12021  // 1.2) Store the edges of the "jproc" halo elements
12022  // **************************************************************
12023  // Go throught halo elements on "jproc" processor
12024  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
12025  {
12026 #ifdef PARANOID
12027  unsigned e =
12028  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
12029  // Only work with halo elements inside the "jproc" processor
12030  if (element_domain[e] != iproc)
12031  {
12032  // There was a problem on the jhalo-ihalo classification
12033  std::stringstream err;
12034  err << "There was a problem on the jhalo-ihalo classification.\n"
12035  << "One of the elements, (the one with the (" << e << ")-th "
12036  << "index ) is not on the (" << iproc << ")-th processor\n"
12037  << "but it was stored as a halo element of processor ("
12038  << jproc << ") with processor (" << iproc << ").\n";
12039  throw OomphLibError(
12040  err.str(),
12041  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12042  OOMPH_EXCEPTION_LOCATION);
12043  }
12044 #endif
12045 
12046  FiniteElement* el_pt =
12047  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
12048  if (el_pt == 0)
12049  {
12050  std::stringstream err;
12051  err << "The halo element (" << jh
12052  << ") could not be casted to the "
12053  << "FiniteElement type.\n";
12054  throw OomphLibError(
12055  err.str(),
12056  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12057  OOMPH_EXCEPTION_LOCATION);
12058  }
12059 
12060 #ifdef PARANOID
12061  // Number of nodes on this element
12062  const unsigned n_nodes = el_pt->nnode();
12063 
12064  // The number of nodes on every element should be at least
12065  // three since we are going to work with the cornes nodes,
12066  // the ones with index 0, 1 and 2
12067  if (n_nodes < 3)
12068  {
12069  std::stringstream err;
12070  err << "The number of nodes of the " << jh
12071  << "-th halo element is"
12072  << " (" << n_nodes << ").\nWe can not work with triangle "
12073  << "elements with less than three nodes\n";
12074  throw OomphLibError(
12075  err.str(),
12076  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12077  OOMPH_EXCEPTION_LOCATION);
12078  }
12079 #endif
12080 
12081  // Get the nodes pointers
12082  Node* first_node_pt = el_pt->node_pt(0);
12083  Node* second_node_pt = el_pt->node_pt(1);
12084  Node* third_node_pt = el_pt->node_pt(2);
12085 
12086  // Store the edges
12087  halo_edges_jproc.push_back(first_node_pt);
12088  halo_edges_jproc.push_back(second_node_pt);
12089  halo_edges_counter_iproc++;
12090 
12091  halo_edges_jproc.push_back(second_node_pt);
12092  halo_edges_jproc.push_back(third_node_pt);
12093  halo_edges_counter_iproc++;
12094 
12095  halo_edges_jproc.push_back(third_node_pt);
12096  halo_edges_jproc.push_back(first_node_pt);
12097  halo_edges_counter_iproc++;
12098 
12099  // Store the info. of the element used to create these edges
12100  std::pair<Node*, Node*> edge1 =
12101  std::make_pair(first_node_pt, second_node_pt);
12102  edgesj_to_element_pt[edge1] = el_pt;
12103 
12104  std::pair<Node*, Node*> edge2 =
12105  std::make_pair(second_node_pt, third_node_pt);
12106  edgesj_to_element_pt[edge2] = el_pt;
12107 
12108  std::pair<Node*, Node*> edge3 =
12109  std::make_pair(third_node_pt, first_node_pt);
12110  edgesj_to_element_pt[edge3] = el_pt;
12111 
12112  // Store the face index of the edge in the element
12113  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
12114  std::make_pair(edge1, el_pt);
12115  edgesj_element_pt_to_face_index[edge_ele1] = 2;
12116 
12117  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
12118  std::make_pair(edge2, el_pt);
12119  edgesj_element_pt_to_face_index[edge_ele2] = 0;
12120 
12121  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
12122  std::make_pair(edge3, el_pt);
12123  edgesj_element_pt_to_face_index[edge_ele3] = 1;
12124 
12125  } // for (jh < nhalo_elements_jproc_with_iproc)
12126 
12127  // ***************************************************************
12128  // SECOND PART
12129  // 1) We already have the information of the edges on the iproc
12130  // halo and jproc halo elements
12131  // 2) Identify the shared edges to create the shared boundaries
12132  // (Only store the information but do not create the polyline)
12133  // ***************************************************************
12134 
12135  // Get the number of edges from each processor
12136  unsigned nhalo_iedges = halo_edges_iproc.size();
12137  unsigned nhalo_jedges = halo_edges_jproc.size();
12138 
12139  // Start comparing the edges to check which of those are
12140  // shared between the "ihalo_edge" and the "jhalo_edge"
12141  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe += 2)
12142  {
12143  // Get the ihe-th edge (pair of nodes)
12144  Vector<Node*> ihalo_edge(2);
12145  ihalo_edge[0] = halo_edges_iproc[ihe];
12146  ihalo_edge[1] = halo_edges_iproc[ihe + 1];
12147 
12148  // Create the pair that defines the edge
12149  std::pair<Node*, Node*> tmp_edge =
12150  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12151 
12152  // Check if the edge lies on a boundary (default values is
12153  // -1 for no association with an internal boundary)
12154  int edge_boundary_id = -1;
12155  {
12156  std::map<std::pair<Node*, Node*>, unsigned>::iterator it;
12157  it = elements_edges_on_boundary.find(tmp_edge);
12158  // If the edges lie on a boundary then get the boundary id
12159  // on which the edges lie
12160  if (it != elements_edges_on_boundary.end())
12161  {
12162  // Assign the internal boundary id associated with the
12163  // edge
12164  edge_boundary_id = (*it).second;
12165  }
12166  else
12167  {
12168  // Look for the reversed version of the edge (the nodes
12169  // inverted)
12170  std::pair<Node*, Node*> rtmp_edge =
12171  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12172  it = elements_edges_on_boundary.find(rtmp_edge);
12173  if (it != elements_edges_on_boundary.end())
12174  {
12175  // Assign the internal boundary id associated with the
12176  // edge
12177  edge_boundary_id = (*it).second;
12178  }
12179  }
12180  }
12181 
12182  // Go through the jhalo_edge and compare with the
12183  // ihalo_edge
12184  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe += 2)
12185  {
12186  // Get the jhe-th edge (pair of nodes)
12187  Vector<Node*> jhalo_edge(2);
12188  jhalo_edge[0] = halo_edges_jproc[jhe];
12189  jhalo_edge[1] = halo_edges_jproc[jhe + 1];
12190 
12191  // Comparing pointer of nodes
12192  if (ihalo_edge[0] == jhalo_edge[0] &&
12193  ihalo_edge[1] == jhalo_edge[1])
12194  {
12195  // Create the edge (both nodes that make the edge)
12196  std::pair<Node*, Node*> new_edge =
12197  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12198 
12199  // Get the elements involved in the creation of the
12200  // edge to check that there are elements associated to
12201  // the edge
12202  FiniteElement* haloi_ele_pt = 0;
12203  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12204  FiniteElement* haloj_ele_pt = 0;
12205  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12206 
12207  // Verify that there is an element associated with it
12208  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12209  {
12210  std::stringstream err;
12211  err << "There is no associated elements with the new "
12212  << "shared boundary. This is an storing problem,\n"
12213  << "possibly related with a memory leak problem!!!\n"
12214  << "The nodes that compound the edge are these:\n"
12215  << "On processor (" << iproc << "):\n"
12216  << "(" << ihalo_edge[0]->x(0) << ", "
12217  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12218  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12219  << "On processor (" << jproc << "):\n"
12220  << "(" << jhalo_edge[0]->x(0) << ", "
12221  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12222  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12223  << "The nodes coordinates should be the same!!!\n";
12224  throw OomphLibError(err.str(),
12225  "TriangleMesh::create_polylines_from_"
12226  "halo_elements_helper()",
12227  OOMPH_EXCEPTION_LOCATION);
12228  }
12229 
12230  // Store the edge
12231  edges[iproc][jproc].push_back(new_edge);
12232 
12233  // Is the edge overlapped by a shared boundary
12234  if (edge_boundary_id >= 0)
12235  {
12236  // Mark the edge as overlapped
12237  overlapped_edge[new_edge] = true;
12238 
12239  // Also mark the reversed edge
12240  std::pair<Node*, Node*> rev_new_edge =
12241  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12242 
12243  // Mark the edge as overlapped
12244  overlapped_edge[rev_new_edge] = true;
12245 
12246  } // if (edge_boundary_id >= 0)
12247 
12248  // Store the internal boundary id (default -1)
12249  // associated to the edge
12250  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12251 
12252  // Store the two elements associated with the edge
12253  Vector<FiniteElement*> tmp_elements_pt;
12254  tmp_elements_pt.push_back(haloi_ele_pt);
12255  tmp_elements_pt.push_back(haloj_ele_pt);
12256 
12257  // Associate the edge with the elements that gave rise to it
12258  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12259 
12260  // Get the face index on each element that gave rise to
12261  // the edge
12262 
12263  // .. first create the pair (edge, finite_element)
12264  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12265  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12266 
12267  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12268  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12269 
12270  // Set default values to later check if values were
12271  // read from the map structure
12272  int face_index_haloi_ele = -1;
12273  face_index_haloi_ele =
12274  edgesi_element_pt_to_face_index[edge_elementi_pair];
12275  int face_index_haloj_ele = -1;
12276  face_index_haloj_ele =
12277  edgesj_element_pt_to_face_index[edge_elementj_pair];
12278  // Verify that there is an element associated with it
12279  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12280  {
12281  std::stringstream err;
12282  err << "There is no associated face indexes to the"
12283  << "elements that gave\nrise to the shared edge\n"
12284  << "The nodes that compound the edge are these:\n"
12285  << "On processor (" << iproc << "):\n"
12286  << "(" << ihalo_edge[0]->x(0) << ", "
12287  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12288  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12289  << "On processor (" << jproc << "):\n"
12290  << "(" << jhalo_edge[0]->x(0) << ", "
12291  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12292  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12293  << "The nodes coordinates should be the same!!!\n";
12294  throw OomphLibError(err.str(),
12295  "TriangleMesh::create_polylines_from_"
12296  "halo_elements_helper()",
12297  OOMPH_EXCEPTION_LOCATION);
12298  } // if (face_index_haloi_ele == -1 ||
12299  // face_index_haloj_ele == -1)
12300 
12301  // Get the face indexes from the map structure
12302  Vector<int> tmp_edge_element_face_index;
12303  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12304  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12305  // Store the face indexes
12306  edge_element_face[iproc][jproc].push_back(
12307  tmp_edge_element_face_index);
12308 
12309  break; // break for (jhe < nhalo_jedges) since edge
12310  // found
12311 
12312  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12313  // ihalo_edge[1] == jhalo_edge[1])
12314  // Comparing nodes pointers
12315  else if (ihalo_edge[0] == jhalo_edge[1] &&
12316  ihalo_edge[1] == jhalo_edge[0])
12317  {
12318  // Create the edge (both nodes that make the edge)
12319  std::pair<Node*, Node*> new_edge =
12320  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12321 
12322  // Get the elements involved in the creation of the
12323  // edge
12324  FiniteElement* haloi_ele_pt = 0;
12325  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12326 
12327  FiniteElement* haloj_ele_pt = 0;
12328  // Create the edge (reversed, that is how it was
12329  // originally stored)
12330  std::pair<Node*, Node*> new_edge_reversed =
12331  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12332  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12333 
12334  // Verify that there is an element associated with it
12335  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12336  {
12337  std::stringstream err;
12338  err << "There is no associated elements with the new "
12339  << "shared boundary (reversed version). This is an "
12340  << "storing problem, possibly related with a memory "
12341  << "leak problem!!!\n"
12342  << "The nodes that compound the edge are these:\n"
12343  << "On processor (" << iproc << "):\n"
12344  << "(" << ihalo_edge[0]->x(0) << ", "
12345  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12346  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12347  << "On processor (" << jproc << "):\n"
12348  << "(" << jhalo_edge[0]->x(0) << ", "
12349  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12350  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12351  << "The nodes coordinates should be the same!!!\n";
12352  throw OomphLibError(err.str(),
12353  "TriangleMesh::create_polylines_from_"
12354  "halo_elements_helper()",
12355  OOMPH_EXCEPTION_LOCATION);
12356  }
12357 
12358  // Store the edge
12359  edges[iproc][jproc].push_back(new_edge);
12360 
12361  // Is the edge overlapped by a shared boundary
12362  if (edge_boundary_id >= 0)
12363  {
12364  // Mark the edge as overlapped
12365  overlapped_edge[new_edge] = true;
12366 
12367  // Also mark the reversed edge
12368  std::pair<Node*, Node*> rev_new_edge =
12369  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12370 
12371  // Mark the edge as overlapped
12372  overlapped_edge[rev_new_edge] = true;
12373  } // if (edge_boundary_id >= 0)
12374 
12375  // Store the internal boundary id (default -1)
12376  // associated to the edge
12377  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12378 
12379  // Store the two elements associated with the edge
12380  Vector<FiniteElement*> tmp_elements_pt;
12381  tmp_elements_pt.push_back(haloi_ele_pt);
12382  tmp_elements_pt.push_back(haloj_ele_pt);
12383 
12384  // Associate the edge with the elements that gave rise to it
12385  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12386 
12387  // Get the face index on each element that gave rise to
12388  // the edge
12389 
12390  // .. first create the pair (edge, finite_element)
12391  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12392  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12393 
12394  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12395  edge_elementj_pair =
12396  make_pair(new_edge_reversed, haloj_ele_pt);
12397 
12398  // Set default values to later check if values were
12399  // read from the map structure
12400  int face_index_haloi_ele = -1;
12401  face_index_haloi_ele =
12402  edgesi_element_pt_to_face_index[edge_elementi_pair];
12403  int face_index_haloj_ele = -1;
12404  face_index_haloj_ele =
12405  edgesj_element_pt_to_face_index[edge_elementj_pair];
12406  // Verify that there is an element associated with it
12407  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12408  {
12409  std::stringstream err;
12410  err << "There is no associated face indexes to the"
12411  << "elements that gave\nrise to the shared edge\n"
12412  << "The nodes that compound the edge are these:\n"
12413  << "On processor (" << iproc << "):\n"
12414  << "(" << ihalo_edge[0]->x(0) << ", "
12415  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12416  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12417  << "On processor (" << jproc << "):\n"
12418  << "(" << jhalo_edge[0]->x(0) << ", "
12419  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12420  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12421  << "The nodes coordinates should be the same!!!\n";
12422  throw OomphLibError(err.str(),
12423  "TriangleMesh::create_polylines_from_"
12424  "halo_elements_helper()",
12425  OOMPH_EXCEPTION_LOCATION);
12426  } // if (face_index_haloi_ele == -1 ||
12427  // face_index_haloj_ele == -1)
12428 
12429  // Get the face indexes from the map structure
12430  Vector<int> tmp_edge_element_face_index;
12431  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12432  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12433  // Store the face indexes
12434  edge_element_face[iproc][jproc].push_back(
12435  tmp_edge_element_face_index);
12436 
12437  break; // break for (jhe < nhalo_jedges) since edge found
12438 
12439  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12440  // ihalo_edge[1] == jhalo_edge[0])
12441 
12442  } // for (jhe < nhaloj_edges)
12443 
12444  } // for (ihe < nhaloi_edges)
12445 
12446  } // if (nhalo_elements_iproc_with_jproc > 0)
12447 
12448  } // for (jproc < nproc)
12449 
12450  } // for (iproc < nproc)
12451 
12452  // ------------------------------------------------------------------
12453  // Compute the degree of each node in the shared edges
12454  // ------------------------------------------------------------------
12455 
12456  // Visit all the shared edges between each pair of processors,
12457  // visit the nodes of each edge and compute the degree of each node
12458 
12459  // Store the degree (valency) of each node
12460  std::map<Node*, unsigned> global_shared_node_degree;
12461 
12462 #ifdef PARANOID
12463  // Map to check if an edge has been already visited
12464  std::map<std::pair<Node*, Node*>, bool> edge_done;
12465 #endif // #ifdef PARANOID
12466  // Map to check if a node has been already visited
12467  std::map<Node*, bool> node_done;
12468 
12469  // Loop over the processors and get the shared edged between each
12470  // pair of processors
12471  for (unsigned iproc = 0; iproc < nproc; iproc++)
12472  {
12473  // Start from iproc + 1 to avoid checking with itself (there is
12474  // no shared edges between the same processor), and to avoid
12475  // double counting the edges and nodes (the shared edges between
12476  // processor (iproc, jproc) are the same as those between
12477  // processor jproc, iproc)
12478  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12479  {
12480  // Get the number of edges shared between the pair of processors
12481  const unsigned nshd_edges = edges[iproc][jproc].size();
12482 #ifdef PARANOID
12483  // There must be the same number of information on each of the
12484  // containers
12485 
12486  // Get the number of edge elements
12487  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12488  if (nshd_edges != nedge_element)
12489  {
12490  std::stringstream error_message;
12491  error_message
12492  << "The number of shared edges between processor iproc and jproc\n"
12493  << "is different form the number of edge elements between the\n"
12494  << "pair of processors\n"
12495  << "iproc: (" << iproc << ")\n"
12496  << "jproc: (" << jproc << ")\n"
12497  << "# of shared edges: (" << nshd_edges << ")\n"
12498  << "# of edge elements: (" << nedge_element << ")\n\n";
12499  throw OomphLibError(
12500  error_message.str(),
12501  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12502  OOMPH_EXCEPTION_LOCATION);
12503  }
12504 
12505  // Get the number of edge element faces
12506  const unsigned nedge_element_face =
12507  edge_element_face[iproc][jproc].size();
12508  if (nshd_edges != nedge_element_face)
12509  {
12510  std::stringstream error_message;
12511  error_message
12512  << "The number of shared edges between processor iproc and jproc\n"
12513  << "is different form the number of edge element faces between "
12514  "the\n"
12515  << "pair of processors\n"
12516  << "iproc: (" << iproc << ")\n"
12517  << "jproc: (" << jproc << ")\n"
12518  << "# of shared edges: (" << nshd_edges << ")\n"
12519  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12520  throw OomphLibError(
12521  error_message.str(),
12522  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12523  OOMPH_EXCEPTION_LOCATION);
12524  }
12525 
12526  // Get the number of edge boundaries
12527  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12528  if (nshd_edges != nedge_boundary)
12529  {
12530  std::stringstream error_message;
12531  error_message
12532  << "The number of shared edges between processor iproc and jproc\n"
12533  << "is different form the number of edge boundaries ids between "
12534  "the\n"
12535  << "pair of processors\n"
12536  << "iproc: (" << iproc << ")\n"
12537  << "jproc: (" << jproc << ")\n"
12538  << "# of shared edges: (" << nshd_edges << ")\n"
12539  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12540  throw OomphLibError(
12541  error_message.str(),
12542  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12543  OOMPH_EXCEPTION_LOCATION);
12544  }
12545 
12546 #endif // #ifdef PARANOID
12547 
12548  // Loop over the shared edges between (iproc, jproc) processors
12549  for (unsigned se = 0; se < nshd_edges; se++)
12550  {
12551  // Get the edge
12552  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12553 #ifdef PARANOID
12554  // Check that the edge has not been previously visited
12555  if (edge_done[edge])
12556  {
12557  std::stringstream error_message;
12558  error_message
12559  << "The shared edge between processor iproc and processor\n"
12560  << "jproc has been already visited, this is weird since the\n"
12561  << "edge should not be shared by other pair of processors\n"
12562  << "iproc: (" << iproc << ")\n"
12563  << "jproc: (" << jproc << ")\n"
12564  << "First node of edge: (" << edge.first->x(0) << ", "
12565  << edge.first->x(1) << ")\n"
12566  << "Second node of edge: (" << edge.second->x(0) << ", "
12567  << edge.second->x(1) << ")\n"
12568  << "Associated edge boundary id: ("
12569  << edge_boundary[iproc][jproc][se] << ")\n\n";
12570  throw OomphLibError(
12571  error_message.str(),
12572  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12573  OOMPH_EXCEPTION_LOCATION);
12574  }
12575 
12576  // Mark the edge as done
12577  edge_done[edge] = true;
12578  // Create the reversed version and include it too
12579  std::pair<Node*, Node*> rev_edge =
12580  std::make_pair(edge.second, edge.first);
12581  // Mark reversed edge as done
12582  edge_done[rev_edge] = true;
12583 #endif // #ifdef PARANOID
12584 
12585  // Get each of the nodes that conform the edge
12586  Node* left_node_pt = edge.first;
12587  Node* right_node_pt = edge.second;
12588 
12589  // Check if the left node has been already done
12590  if (!node_done[left_node_pt])
12591  {
12592  // Set the degree of the node to once since this is the
12593  // first time it has been found
12594  global_shared_node_degree[left_node_pt] = 1;
12595 
12596  } // if (!done_node[left_node_pt])
12597  else
12598  {
12599  // Increase the degree of the node
12600  global_shared_node_degree[left_node_pt]++;
12601  }
12602 
12603  // Check if the right node has been already done
12604  if (!node_done[right_node_pt])
12605  {
12606  // Set the degree of the node to once since this is the
12607  // first time it has been found
12608  global_shared_node_degree[right_node_pt] = 1;
12609  } // if (!done_node[right_node_pt])
12610  else
12611  {
12612  // Increase the degree of the node
12613  global_shared_node_degree[right_node_pt]++;
12614  }
12615 
12616  } // for (se < nshd_edges)
12617 
12618  } // for (jproc < nproc)
12619 
12620  } // for (iproc < nproc)
12621 
12622  // -----------------------------------------------------------------
12623  // Identify those nodes living on edges of original boundaries not
12624  // overlapped by a shared boundary
12625 
12626  // Mark the nodes on original boundaries not overlapped by shared
12627  // boundaries
12628  std::map<unsigned, std::map<Node*, bool>>
12629  node_on_bnd_not_overlapped_by_shd_bnd;
12630 
12631  // Loop over the edges of the original boundaries
12632  for (std::map<std::pair<Node*, Node*>, unsigned>::iterator it_map =
12633  elements_edges_on_boundary.begin();
12634  it_map != elements_edges_on_boundary.end();
12635  it_map++)
12636  {
12637  // Get the edge
12638  std::pair<Node*, Node*> edge_pair = (*it_map).first;
12639 
12640  // Is the edge overlaped by a shared boundary
12641  if (!overlapped_edge[edge_pair])
12642  {
12643  // Mark the nodes of the edge as being on an edge not overlaped
12644  // by a shared boundary on the boundary the edge is
12645  unsigned b = (*it_map).second;
12646 
12647  // Get the left node
12648  Node* left_node_pt = edge_pair.first;
12649  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12650 
12651  // Get the right node
12652  Node* right_node_pt = edge_pair.second;
12653  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12654 
12655  } // if (!overlapped_edge[edge_pair])
12656 
12657  } // Loop over edges to mark those nodes on overlaped edge by
12658  // shared boundaries
12659 
12660  // ------------------------------------------------------------------
12661  // Now create the shared polylines but including the degree of the
12662  // nodes as a nw stop condition for adding more edges to the side
12663  // or a root edge
12664  // ------------------------------------------------------------------
12665 
12666  // Storage for new created polylines with "each processor", non
12667  // sorted (shared polylines of the current processor only)
12668  Vector<Vector<TriangleMeshPolyLine*>> unsorted_polylines_pt(nproc);
12669 
12670  // Map that associates the shared boundary id with the list of
12671  // nodes that create it (shared boundary of the current processor
12672  // only)
12673  std::map<unsigned, std::list<Node*>> shared_bnd_id_to_sorted_list_node_pt;
12674 
12675  // Get maximum user boundary id and set the initial shared boundary
12676  // id
12677  unsigned shared_boundary_id_start = this->nboundary();
12678  Initial_shared_boundary_id = shared_boundary_id_start;
12679 
12680  // Aqui
12681 
12682  // Loop over the processors and get the shared edged between each
12683  // pair of processors
12684  for (unsigned iproc = 0; iproc < nproc; iproc++)
12685  {
12686  // Start from iproc + 1 to avoid checking with itself (there is
12687  // no shared edges between the same processor), and to avoid
12688  // double counting the edges and nodes (the shared edges between
12689  // processor (iproc, jproc) are the same as those between
12690  // processor jproc, iproc)
12691  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12692  {
12693  // *************************************************************
12694  // THIRD PART
12695  // 1) Sort the edges (make them contiguous) so that they can
12696  // be used as the vertex coordinates that define a shared
12697  // boundary (polyline)
12698  // *************************************************************
12699  unsigned npolylines_counter = 0;
12700  const unsigned nedges = edges[iproc][jproc].size();
12701 
12702  // -----------------------------------------------------------
12703  // Compute all the SHARED POLYLINES
12704  // -----------------------------------------------------------
12705  // The number of sorted edges
12706  unsigned nsorted_edges = 0;
12707 
12708  // Keep track of the already done edges
12709  std::map<std::pair<Node*, Node*>, bool> edge_done;
12710 
12711  // Loop over all the edges to create all the polylines with
12712  // the current processors involved
12713  while (nsorted_edges < nedges)
12714  {
12715  // Temporaly storage for the elements associated to the
12716  // sorted edges
12717  std::list<FiniteElement*> tmp_boundary_element_pt;
12718  // Temporly storage for the face indexes on the element
12719  // that created the given edge
12720  std::list<int> tmp_face_index_element;
12721  // Get an initial pair of nodes to create an edge
12722  std::pair<Node*, Node*> edge;
12723 #ifdef PARANOID
12724  bool found_initial_edge = false;
12725 #endif
12726  int root_edge_bound_id = -1;
12727  unsigned iedge = 0;
12728  for (iedge = 0; iedge < nedges; iedge++)
12729  {
12730  edge = edges[iproc][jproc][iedge];
12731  // If not done then take it as initial edge
12732  if (!edge_done[edge])
12733  {
12734  // Get the boundary id that the edge may be overlapping
12735  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12736 #ifdef PARANOID
12737  found_initial_edge = true;
12738 #endif
12739  nsorted_edges++;
12740  iedge++;
12741  break;
12742  } // if (!edge_done[edge])
12743  } // for (iedge < nedges)
12744 
12745 #ifdef PARANOID
12746  if (!found_initial_edge)
12747  {
12748  std::ostringstream error_message;
12749  error_message
12750  << "All the edge are already done, but the number of done\n"
12751  << "edges (" << nsorted_edges
12752  << ") is still less than the total\n"
12753  << "number of edges (" << nedges << ").\n";
12754  // << "----- Possible memory leak -----\n";
12755  throw OomphLibError(
12756  error_message.str(),
12757  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12758  OOMPH_EXCEPTION_LOCATION);
12759  }
12760 #endif
12761 
12762  // Storing for the sorting nodes extracted from the
12763  // edges. The sorted nodes are used to create a polyline
12764  std::list<Node*> sorted_nodes;
12765  sorted_nodes.clear();
12766 
12767  // The initial and final nodes of the list
12768  Node* first_node_pt = edge.first;
12769  Node* last_node_pt = edge.second;
12770 
12771  // Push back on the list the new edge (nodes)
12772  sorted_nodes.push_back(first_node_pt);
12773  sorted_nodes.push_back(last_node_pt);
12774 
12775  // Get the elements associated to the edge and store them
12776  // in the temporaly boundary elements storage
12777  tmp_boundary_element_pt.push_back(
12778  edge_element_pt[iproc][jproc][iedge - 1][0]);
12779  tmp_boundary_element_pt.push_back(
12780  edge_element_pt[iproc][jproc][iedge - 1][1]);
12781 
12782  // ... then get the face index of the element from where
12783  // the edge came from
12784  tmp_face_index_element.push_back(
12785  edge_element_face[iproc][jproc][iedge - 1][0]);
12786  tmp_face_index_element.push_back(
12787  edge_element_face[iproc][jproc][iedge - 1][1]);
12788 
12789  // Mark edge as done
12790  edge_done[edge] = true;
12791 
12792  // Continue iterating if a new node (that creates a new
12793  // edge) is added to the list, we have just added two nodes
12794  // (the first and last of the root edge)
12795  bool node_added = true;
12796 
12797  // Flags to indicate at which end the node was added (left
12798  // or right)
12799  bool node_added_to_the_left = true;
12800  bool node_added_to_the_right = true;
12801 
12802  // The nodes that create a shared boundary are obtained by
12803  // connecting the edges shared by the halo and haloed
12804  // elements. These edges are connected to left or right of
12805  // the shared boundary. Every time a new edge is added to
12806  // the left (or right), the most left (or right) node is
12807  // searched in the list of nodes of previous shared
12808  // boundaries, if the node is found then it is said to be
12809  // shared with another boundary and a connection to that
12810  // boundary needs to be specified. We stop adding edges
12811  // (and nodes) to the side where that nodes was found to be
12812  // shared. Note that the intersection (shared node) may be
12813  // with the same shared boundary
12814 
12815  // Flag to indicate a node was found to be shared with
12816  // another boundary at the left end (most left node) of the
12817  // shared boundary
12818  bool connection_to_the_left = false;
12819 
12820  // Flag to indicate a node was found to be shared with
12821  // another boundary at the right end (most right node) of
12822  // the shared boundary
12823  bool connection_to_the_right = false;
12824 
12825  // Flag to stop the adding of edges (and nodes) to the
12826  // current shared boundary
12827  bool current_polyline_has_connections_at_both_ends = false;
12828 
12829  // Store the boundary ids of the polylines to connect (only
12830  // used when the polyline was found to have a connection)
12831  // -1: Indicates no connection
12832  // -2: Indicates connection with itself
12833  // Any other value: Boundary id to connect
12834  int bound_id_connection_to_the_left = -1;
12835  int bound_id_connection_to_the_right = -1;
12836 
12837  // Get the degree of the first node
12838  const unsigned first_node_degree =
12839  global_shared_node_degree[first_node_pt];
12840 
12841  // Check if the nodes of the root edge have connections
12842  // ... to the left
12843  bound_id_connection_to_the_left = check_connections_of_polyline_nodes(
12844  element_in_processor_pt,
12845  root_edge_bound_id,
12846  overlapped_edge,
12847  node_on_bnd_not_overlapped_by_shd_bnd,
12848  sorted_nodes,
12849  shared_bnd_id_to_sorted_list_node_pt,
12850  first_node_degree,
12851  first_node_pt);
12852 
12853  // If there is a connection then set the
12854  // corresponding flag
12855  // (-1): No connection
12856  // (-2): Connection with itself
12857  // (-3): No connection, stop adding nodes
12858  // (other value): Boundary id
12859  if (bound_id_connection_to_the_left != -1)
12860  {
12861  connection_to_the_left = true;
12862  } // if (bound_id_connection_to_the_left != -1)
12863 
12864  // Get the degree of the last node
12865  const unsigned last_node_degree =
12866  global_shared_node_degree[last_node_pt];
12867 
12868  // Check if the nodes of the root edge have connections
12869  // ... to the right
12870  bound_id_connection_to_the_right =
12871  check_connections_of_polyline_nodes(
12872  element_in_processor_pt,
12873  root_edge_bound_id,
12874  overlapped_edge,
12875  node_on_bnd_not_overlapped_by_shd_bnd,
12876  sorted_nodes,
12877  shared_bnd_id_to_sorted_list_node_pt,
12878  last_node_degree,
12879  last_node_pt);
12880 
12881  // If there is a connection then set the
12882  // corresponding flag
12883  // (-1): No connection
12884  // (-2): Connection with itself
12885  // (other value): Boundary id
12886  if (bound_id_connection_to_the_right != -1)
12887  {
12888  connection_to_the_right = true;
12889  } // if (bound_id_connection_to_the_right != -1)
12890 
12891  // If the current shared boundary has connections at both
12892  // ends then stop the adding of nodes
12893  if (connection_to_the_left && connection_to_the_right)
12894  {
12895  current_polyline_has_connections_at_both_ends = true;
12896  }
12897 
12898  // Continue searching for more edges if
12899  // 1) A new node was added at the left or right of the list
12900  // 2) There are more edges to possible add
12901  // 3) The added node is not part of any other previous
12902  // shared polyline
12903  while (node_added && (nsorted_edges < nedges) &&
12904  !current_polyline_has_connections_at_both_ends)
12905  {
12906  // Start from the next edge since we have already added
12907  // the previous one as the initial edge (any previous
12908  // edge had to be added to previous polylines)
12909  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12910  {
12911  // Reset the flags for added nodes, to the left and right
12912  node_added = false;
12913  node_added_to_the_left = false;
12914  node_added_to_the_right = false;
12915  // Get the current edge
12916  edge = edges[iproc][jproc][iiedge];
12917  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12918 
12919  // We need to ensure to connect with edges that share
12920  // the same bound id or with those that has no boundary
12921  // id associated (the default -1 value), may apply
12922  // exclusively to internal boundaries
12923  if (!edge_done[edge] && (edge_bound_id == root_edge_bound_id))
12924  {
12925  // Get each individual node
12926  Node* left_node_pt = edge.first;
12927  Node* right_node_pt = edge.second;
12928 
12929  // Pointer to the new added node
12930  Node* new_added_node_pt = 0;
12931 
12932  // Is the node to be added to the left?
12933  if (left_node_pt == first_node_pt && !connection_to_the_left)
12934  {
12935  // Push front the new node
12936  sorted_nodes.push_front(right_node_pt);
12937  // Update the new added node and the first node
12938  new_added_node_pt = first_node_pt = right_node_pt;
12939  // Set the node added flag to true
12940  node_added = true;
12941  // Indicate the node was added to the left
12942  node_added_to_the_left = true;
12943  }
12944  // Is the node to be added to the right?
12945  else if (left_node_pt == last_node_pt &&
12946  !connection_to_the_right)
12947  {
12948  // Push back the new node
12949  sorted_nodes.push_back(right_node_pt);
12950  // Update the new added node and the last node
12951  new_added_node_pt = last_node_pt = right_node_pt;
12952  // Set the node added flag to true
12953  node_added = true;
12954  // Indicate the node was added to the right
12955  node_added_to_the_right = true;
12956  }
12957  // Is the node to be added to the left?
12958  else if (right_node_pt == first_node_pt &&
12959  !connection_to_the_left)
12960  {
12961  // Push front the new node
12962  sorted_nodes.push_front(left_node_pt);
12963  // Update the new added node and the first node
12964  new_added_node_pt = first_node_pt = left_node_pt;
12965  // Set the node added flag to true
12966  node_added = true;
12967  // Indicate the node was added to the left
12968  node_added_to_the_left = true;
12969  }
12970  // Is the node to be added to the right?
12971  else if (right_node_pt == last_node_pt &&
12972  !connection_to_the_right)
12973  {
12974  // Push back the new node
12975  sorted_nodes.push_back(left_node_pt);
12976  // Update the new added node and the last node
12977  new_added_node_pt = last_node_pt = left_node_pt;
12978  // Set the node added flag to true
12979  node_added = true;
12980  // Indicate the node was added to the right
12981  node_added_to_the_right = true;
12982  }
12983 
12984  // If we added a new node then we need to check if
12985  // that node has been already added in other shared
12986  // boundaries (which may define a connection)
12987  if (node_added)
12988  {
12989  // Mark as done only if one of its nodes has been
12990  // added to the list
12991  edge_done[edge] = true;
12992  nsorted_edges++;
12993 
12994  // Get the degree of the added node
12995  const unsigned added_node_degree =
12996  global_shared_node_degree[new_added_node_pt];
12997 
12998  if (node_added_to_the_left)
12999  {
13000  // Add the bulk elements
13001  tmp_boundary_element_pt.push_front(
13002  edge_element_pt[iproc][jproc][iiedge][1]);
13003  tmp_boundary_element_pt.push_front(
13004  edge_element_pt[iproc][jproc][iiedge][0]);
13005  // Add the face elements
13006  tmp_face_index_element.push_front(
13007  edge_element_face[iproc][jproc][iiedge][1]);
13008  tmp_face_index_element.push_front(
13009  edge_element_face[iproc][jproc][iiedge][0]);
13010  }
13011 
13012  if (node_added_to_the_right)
13013  {
13014  // Add the bulk elements
13015  tmp_boundary_element_pt.push_back(
13016  edge_element_pt[iproc][jproc][iiedge][0]);
13017  tmp_boundary_element_pt.push_back(
13018  edge_element_pt[iproc][jproc][iiedge][1]);
13019  // Add the face elements
13020  tmp_face_index_element.push_back(
13021  edge_element_face[iproc][jproc][iiedge][0]);
13022  tmp_face_index_element.push_back(
13023  edge_element_face[iproc][jproc][iiedge][1]);
13024  }
13025 
13026  // Based on which side the node was added, look for
13027  // connections on that side
13028 
13029  // Verify for connections to the left (we need to
13030  // check for the connection variable too, since
13031  // after a connection has been done we no longer
13032  // need to verify for this condition)
13033  if (node_added_to_the_left && !connection_to_the_left)
13034  {
13035  // Check for connection
13036  bound_id_connection_to_the_left =
13037  check_connections_of_polyline_nodes(
13038  element_in_processor_pt,
13039  root_edge_bound_id,
13040  overlapped_edge,
13041  node_on_bnd_not_overlapped_by_shd_bnd,
13042  sorted_nodes,
13043  shared_bnd_id_to_sorted_list_node_pt,
13044  added_node_degree,
13045  new_added_node_pt);
13046 
13047  // If there is a connection then set the
13048  // corresponding flag
13049  // (-1): No connection
13050  // (-2): Connection with itself
13051  // (other value): Boundary id
13052  if (bound_id_connection_to_the_left != -1)
13053  {
13054  connection_to_the_left = true;
13055  } // if (bound_id_connection_to_the_left != -1)
13056 
13057  } // if (node_added_to_the_left &&
13058  // !connection_to_the_left)
13059 
13060  // Verify for connections to the right (we need to
13061  // check for the connection variable too, since
13062  // after a connection has been done we no longer
13063  // need to verify for this condition)
13064  if (node_added_to_the_right && !connection_to_the_right)
13065  {
13066  // Check for connection
13067  bound_id_connection_to_the_right =
13068  check_connections_of_polyline_nodes(
13069  element_in_processor_pt,
13070  root_edge_bound_id,
13071  overlapped_edge,
13072  node_on_bnd_not_overlapped_by_shd_bnd,
13073  sorted_nodes,
13074  shared_bnd_id_to_sorted_list_node_pt,
13075  added_node_degree,
13076  new_added_node_pt);
13077 
13078  // If there is a connection then set the
13079  // corresponding flag
13080  // (-1): No connection
13081  // (-2): Connection with itself
13082  // (other value): Boundary id
13083  if (bound_id_connection_to_the_right != -1)
13084  {
13085  connection_to_the_right = true;
13086  } // if (bound_id_connection_to_the_right != -1)
13087 
13088  } // if (node_added_to_the_right &&
13089  // !connection_to_the_right)
13090 
13091  // If the current shared boundary has connections
13092  // at both ends then stop the adding of nodes
13093  if (connection_to_the_left && connection_to_the_right)
13094  {
13095  current_polyline_has_connections_at_both_ends = true;
13096  }
13097 
13098  // Break the for and re-start to look more edges to
13099  // the left or right
13100  break;
13101 
13102  } // if (node_added)
13103 
13104  } // if (!edge_done[edge])
13105  } // for (iiedge < nedges)
13106 
13107  } // while(node_added && (nsorted_edges < nedges)
13108  // && !current_polyline_has_connections_at_both_ends)
13109 
13110  // ------------------------------------------------------------
13111  // If the sorted nodes of the shared polyline create a loop
13112  // it is necessary to break it by creating as many
13113  // polylines as required
13114 
13115  // Change the list to a vector representation of the
13116  // boundary elements and the face indexes
13117 
13118  // Get the number of boundary elements
13119  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
13120 
13121  // Storage for the boundary elements and face indexes
13122  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
13123  Vector<int> tmp_face_idx_ele(n_bnd_ele);
13124  // Helper counter
13125  unsigned help_counter = 0;
13126  // Fill the data structures
13127  for (std::list<FiniteElement*>::iterator it_bnd_ele =
13128  tmp_boundary_element_pt.begin();
13129  it_bnd_ele != tmp_boundary_element_pt.end();
13130  it_bnd_ele++)
13131  {
13132  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
13133  }
13134 
13135  // Restart counter
13136  help_counter = 0;
13137  for (std::list<int>::iterator it_face_idx =
13138  tmp_face_index_element.begin();
13139  it_face_idx != tmp_face_index_element.end();
13140  it_face_idx++)
13141  {
13142  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
13143  }
13144 
13145  // Store the nodes for the new shared polylines without
13146  // loops
13147  Vector<std::list<Node*>> final_sorted_nodes_pt;
13148  // Store the boundary elements of the shared polyline
13149  // without loops
13150  Vector<Vector<FiniteElement*>> final_boundary_element_pt;
13151  // Face indexes of the boundary elements without loops
13152  Vector<Vector<int>> final_face_index_element;
13153  // Connection flags (to the left) of the shared boundaries
13154  // without loops
13155  Vector<int> final_bound_id_connection_to_the_left;
13156  // Connection flags (to the right) of the shared boundaries
13157  // without loops
13158  Vector<int> final_bound_id_connection_to_the_right;
13159 
13160  // Break any possible loop created by the shared polyline
13161  break_loops_on_shared_polyline_helper(
13162  shared_boundary_id_start,
13163  sorted_nodes,
13164  tmp_bnd_ele_pt,
13165  tmp_face_idx_ele,
13166  bound_id_connection_to_the_left,
13167  bound_id_connection_to_the_right,
13168  final_sorted_nodes_pt,
13169  final_boundary_element_pt,
13170  final_face_index_element,
13171  final_bound_id_connection_to_the_left,
13172  final_bound_id_connection_to_the_right);
13173 
13174  // Get the number of final sorted nodes
13175  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
13176 
13177  // Loop over the list of final sorted nodes
13178  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13179  {
13180  // --------------------------------------------------------
13181  // Associate the list of sorted nodes with the boundary id
13182  // of the shared boundary that is going to be crated
13183  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13184  final_sorted_nodes_pt[i];
13185 
13186  // Create the shared polyline and fill the data
13187  // structured associated to it
13188  create_shared_polyline(my_rank,
13189  shared_boundary_id_start,
13190  iproc,
13191  jproc,
13192  final_sorted_nodes_pt[i],
13193  root_edge_bound_id,
13194  final_boundary_element_pt[i],
13195  final_face_index_element[i],
13196  unsorted_polylines_pt,
13197  final_bound_id_connection_to_the_left[i],
13198  final_bound_id_connection_to_the_right[i]);
13199 
13200  // Increase the register for the number of created shared
13201  // polylines
13202  npolylines_counter++;
13203 
13204  // Increase the boundary id (the one that will be used by
13205  // the next shared boundary)
13206  shared_boundary_id_start++;
13207 
13208  } // for (i < n_final_sorted_nodes)
13209 
13210  } // while(nsorted_edges < nedges);
13211 
13212  } // for (jproc < nproc)
13213 
13214  // We already have all the shared polylines (shared boundaries)
13215  // of processor iproc with processor jproc. Now we sort them so
13216  // that they be contiguous and can create polygons.
13217 
13218  // If there are polylines to be sorted then sort them
13219  if (unsorted_polylines_pt[iproc].size() > 0)
13220  {
13221  // Now that we have all the new unsorted polylines on "iproc"
13222  // processor it is time to sort them so they be all contiguous
13223  sort_polylines_helper(unsorted_polylines_pt[iproc],
13224  output_polylines_pt[iproc]);
13225  }
13226 
13227 #ifdef PARANOID
13228  const unsigned nunsorted_polylines_iproc =
13229  unsorted_polylines_pt[iproc].size();
13230 
13231  // Verify that all the polylines have been sorted
13232  unsigned tmp_ntotal_polylines = 0;
13233  // Count the total number of sorted polylines
13234  for (unsigned ii = 0; ii < output_polylines_pt[iproc].size(); ii++)
13235  {
13236  tmp_ntotal_polylines += output_polylines_pt[iproc][ii].size();
13237  }
13238  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13239  {
13240  std::ostringstream error_message;
13241  error_message << " The total number of unsorted polylines ("
13242  << nunsorted_polylines_iproc
13243  << ") in common with\nprocessor (" << iproc
13244  << ") is different from the total number of sorted "
13245  << "polylines (" << tmp_ntotal_polylines
13246  << ") with\nthe same "
13247  << "proessor\n";
13248  throw OomphLibError(error_message.str(),
13249  OOMPH_CURRENT_FUNCTION,
13250  OOMPH_EXCEPTION_LOCATION);
13251  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13252 #endif
13253 
13254  } // for (iproc < nproc)
13255 
13256  // Establish the last used boundary id
13257  this->Final_shared_boundary_id = shared_boundary_id_start;
13258  }
13259 
13260  // ======================================================================
13261  // \short Break any possible loop created by the sorted list of nodes
13262  // that is used to create a new shared polyline
13263  // ======================================================================
13264  template<class ELEMENT>
13266  const unsigned& initial_shd_bnd_id,
13267  std::list<Node*>& input_nodes,
13268  Vector<FiniteElement*>& input_boundary_element_pt,
13269  Vector<int>& input_face_index_element,
13270  const int& input_connect_to_the_left,
13271  const int& input_connect_to_the_right,
13272  Vector<std::list<Node*>>& output_sorted_nodes_pt,
13273  Vector<Vector<FiniteElement*>>& output_boundary_element_pt,
13274  Vector<Vector<int>>& output_face_index_element,
13275  Vector<int>& output_connect_to_the_left,
13276  Vector<int>& output_connect_to_the_right)
13277  {
13278  // Get the left and right node of the current list of sorted nodes
13279  Node* left_node_pt = input_nodes.front();
13280  Node* right_node_pt = input_nodes.back();
13281 
13282  // Temporary storage for list of nodes, boundary elements and face
13283  // element's indexes
13284  Vector<std::list<Node*>> tmp_sub_nodes;
13285  Vector<Vector<FiniteElement*>> tmp_sub_bnd_ele_pt;
13286  Vector<Vector<int>> tmp_sub_face_idx_ele;
13287 
13288  // Iterator for the list of input nodes
13289  std::list<Node*>::iterator it = input_nodes.begin();
13290 
13291  // Counter
13292  unsigned counter = 0;
13293 
13294  // Loop while not all nodes have been done
13295  while (it != input_nodes.end())
13296  {
13297  // Check if the current node is the final one
13298  it++;
13299  // Is the current node the final node?
13300  if (it == input_nodes.end())
13301  {
13302  // Break, add no more nodes
13303  break;
13304  }
13305  else
13306  {
13307  // Restore the iterator
13308  it--;
13309  }
13310 
13311  // Get a list of nonrepeated nodes
13312  std::list<Node*> sub_nodes;
13313  // The temporary vector of boundary elements associated with the
13314  // nodes
13315  Vector<FiniteElement*> sub_bnd_ele_pt;
13316  // The temporary vector of face indexes associated with the
13317  // boundary elements
13318  Vector<int> sub_face_idx_ele;
13319 
13320  // Add the current node to the list
13321  sub_nodes.push_back(*it);
13322 
13323  // Add nodes until found a repeated node (the left or right
13324  // node) or until reaching the end of the list of nodes
13325  do
13326  {
13327  // Go to the next node
13328  ++it;
13329 
13330  // Add the new node
13331  sub_nodes.push_back((*it));
13332 
13333  // Add the boundary elements
13334  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13335  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter + 1]);
13336 
13337  // Add the face indexes
13338  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13339  sub_face_idx_ele.push_back(input_face_index_element[counter + 1]);
13340 
13341  // Increase the counter
13342  counter += 2;
13343 
13344  // Continue adding until reaching a repeated node or the end
13345  // of the list of nodes
13346  } while ((*it) != left_node_pt && (*it) != right_node_pt &&
13347  it != input_nodes.end());
13348 
13349  // Add the sub-set of nodes to the temporary storage
13350  tmp_sub_nodes.push_back(sub_nodes);
13351  // Add the face elements to the temporary storage
13352  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13353  // Add the face indexes to the temporary storage
13354  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13355 
13356  } // while((*it) != input_nodes.end())
13357 
13358  // --------------------------------------------------
13359  // Now create as many shared boundaries as required
13360 
13361  // Get the number of sub-list of nodes created
13362  const unsigned n_sub_list = tmp_sub_nodes.size();
13363 
13364 #ifdef PARANOID
13365  if (n_sub_list > 3)
13366  {
13367  std::stringstream error_message;
13368  error_message
13369  << "The number of sub-list of nodes created from the shared\n"
13370  << "polyline with loops was (" << n_sub_list << ").\n"
13371  << "We can only handle up to three sub-list of nodes\n";
13372  throw OomphLibError(
13373  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13374  }
13375 #endif
13376 
13377  // If there is only one list it may be because there are no loops or
13378  // there is only one loop (a circle)
13379  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13380  {
13381  // There are no loops, return just after filling the data
13382  // structures
13383 
13384  // This is the base case used most of the times
13385 
13386  // Set the vector of lists of nodes
13387  output_sorted_nodes_pt = tmp_sub_nodes;
13388  // Set the vector of boundary elements
13389  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13390  // Set the vector of face indexes
13391  output_face_index_element = tmp_sub_face_idx_ele;
13392 
13393  // Set the connection flags, change them by the proper connection
13394  // flag
13395 
13396 #ifdef PARANOID
13397  if (input_connect_to_the_left == -2)
13398  {
13399  std::stringstream error_message;
13400  error_message
13401  << "The connection flag to the left (" << input_connect_to_the_left
13402  << ") indicates a connection\n"
13403  << "with the same polyline.\n However, only one sub-polyline was "
13404  << "found and no loop\nwas identified\n\n";
13405  throw OomphLibError(error_message.str(),
13406  OOMPH_CURRENT_FUNCTION,
13407  OOMPH_EXCEPTION_LOCATION);
13408  }
13409 #endif
13410 
13411  // The left connection flag
13412  if (input_connect_to_the_left == -3)
13413  {
13414  output_connect_to_the_left.push_back(-1);
13415  }
13416  else
13417  {
13418  output_connect_to_the_left.push_back(input_connect_to_the_left);
13419  }
13420 
13421 #ifdef PARANOID
13422  if (input_connect_to_the_right == -2)
13423  {
13424  std::stringstream error_message;
13425  error_message
13426  << "The connection flag to the right (" << input_connect_to_the_right
13427  << ") indicates a connection\n"
13428  << "with the same polyline.\n However, only one sub-polyline was "
13429  << "found and no loop\nwas identified\n\n";
13430  throw OomphLibError(
13431  error_message.str(),
13432  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13433  OOMPH_EXCEPTION_LOCATION);
13434  }
13435 #endif
13436 
13437  // The right connection flag
13438  if (input_connect_to_the_right == -3)
13439  {
13440  output_connect_to_the_right.push_back(-1);
13441  }
13442  else
13443  {
13444  output_connect_to_the_right.push_back(input_connect_to_the_right);
13445  }
13446 
13447  // Return inmediately
13448  return;
13449  }
13450 
13451  // The temporary storage for the shared boundary id
13452  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13453 
13454  // -----------------------------------------------------------------
13455  // Check all the sub-list of nodes and create two shared boundaries
13456  // from those that make a loop (circle)
13457 
13458  // -----------------------------------------------------------
13459  // Get the left and right node of the first sub-list of nodes
13460  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13461  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13462 
13463  // Check if the sub-list of nodes creates a loop (circle)
13464  if (left_sub_node_pt == right_sub_node_pt)
13465  {
13466  // We need to create two shared polylines and therefore increase
13467  // the shared boundary id by two
13468 
13469  // The first and second half of nodes
13470  std::list<Node*> first_half_node_pt;
13471  std::list<Node*> second_half_node_pt;
13472  // The first and second half of boundary elements
13473  Vector<FiniteElement*> first_half_ele_pt;
13474  Vector<FiniteElement*> second_half_ele_pt;
13475  // The first and second half of face indexes
13476  Vector<int> first_half_face_idx;
13477  Vector<int> second_half_face_idx;
13478 
13479  // Get the number of sub-nodes in the sub-list of nodes
13480  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13481 
13482  // The number of sub-nodes for the first half of the shared
13483  // boundary
13484  const unsigned n_sub_nodes_half =
13485  static_cast<unsigned>(n_sub_nodes / 2.0);
13486 
13487  // Copy as many sub-nodes for the first half of the sub-polyline
13488 
13489  // Iterator to loop over the nodes
13490  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13491 
13492  // Add the first node
13493  first_half_node_pt.push_back(*it_sub);
13494 
13495  // Skip the first node
13496  it_sub++;
13497 
13498  // Counter
13499  unsigned counter_nodes = 0;
13500  unsigned counter2 = 0;
13501 
13502  // Loop to copy the nodes
13503  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
13504  {
13505  // Add the sub-node to the first half
13506  first_half_node_pt.push_back(*it_sub);
13507 
13508  // Add the boundary elements of the first half
13509  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13510  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2 + 1]);
13511  // Add the face indexes of the first half
13512  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13513  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2 + 1]);
13514 
13515  // Increase the counter of added nodes
13516  counter_nodes++;
13517 
13518  // Increase the other counter
13519  counter2 += 2;
13520 
13521  if (counter_nodes == n_sub_nodes_half)
13522  {
13523  // Stop adding to the first half of nodes
13524  break;
13525  }
13526 
13527  } // Copy the first half of nodes
13528 
13529  // The second half
13530 
13531  // Add the first node of the second half
13532  second_half_node_pt.push_back(*it_sub);
13533 
13534  // Skip the first node of the second half
13535  it_sub++;
13536 
13537  // Loop to copy the nodes
13538  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
13539  {
13540  // Add the sub-node to the first half
13541  second_half_node_pt.push_back(*it_sub);
13542 
13543  // Add the boundary elements of the first half
13544  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13545  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2 + 1]);
13546  // Add the face indexes of the first half
13547  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13548  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2 + 1]);
13549 
13550  // Increase the other counter
13551  counter2 += 2;
13552 
13553  } // Copy the second half of nodes
13554 
13555  // Add the sub-list of nodes to the vector of lists of nodes
13556  output_sorted_nodes_pt.push_back(first_half_node_pt);
13557  output_sorted_nodes_pt.push_back(second_half_node_pt);
13558  // Add the sub-vector of elements to the vector of boundary
13559  // elements
13560  output_boundary_element_pt.push_back(first_half_ele_pt);
13561  output_boundary_element_pt.push_back(second_half_ele_pt);
13562  // Add the sub-vector of face indexes to the vector of face
13563  // indexes
13564  output_face_index_element.push_back(first_half_face_idx);
13565  output_face_index_element.push_back(second_half_face_idx);
13566 
13567  // Set the connection flags, change them by the proper connection
13568  // flag
13569 
13570  // ----------------------------------------------------------------
13571  // Connections flags for the first half
13572 
13573  // The left connection flag
13574 
13575  // Connected with nothing but required to stop adding nodes
13576  if (input_connect_to_the_left == -3)
13577  {
13578  // Set connected to nothing
13579  output_connect_to_the_left.push_back(-1);
13580  }
13581  // Connected with itself
13582  else if (input_connect_to_the_left == -2)
13583  {
13584  // Set connected to nothing, this is the base node
13585  output_connect_to_the_left.push_back(-1);
13586  }
13587  else
13588  {
13589  // Any other value keep it
13590  output_connect_to_the_left.push_back(input_connect_to_the_left);
13591  }
13592 
13593  // The right connection flag
13594 
13595  // Set connected to nothing, this is the base node
13596  output_connect_to_the_right.push_back(-1);
13597 
13598  // Increase the shared boundary id
13599  tmp_shd_bnd_id++;
13600 
13601  // ----------------------------------------------------------------
13602  // Connections flags for the second half
13603 
13604  // The left connection flag
13605 
13606  // Set connected to the previous boundary
13607  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13608 
13609  // The right connection flag
13610 
13611  // Are we in the last sub-list of nodes, if that is the case we
13612  // need to respect the flag assigned to the right
13613  if (n_sub_list == 1)
13614  {
13615  if (input_connect_to_the_right == -3)
13616  {
13617  // Set connected to the previous shared boundary id
13618  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13619  }
13620  else if (input_connect_to_the_right == -2)
13621  {
13622  // Set connected to the previous shared boundary id
13623  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13624  }
13625  else if (input_connect_to_the_right == -1)
13626  {
13627  // Set connected to the previous shared boundary id
13628  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13629  }
13630  else
13631  {
13632  // Any other value keep it
13633  output_connect_to_the_right.push_back(input_connect_to_the_right);
13634  }
13635  } // if (n_sub_list == 1)
13636  else
13637  {
13638  // Set connected to the previous shared boundary id
13639  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13640  }
13641 
13642  // Increase the shared boundary id
13643  tmp_shd_bnd_id++;
13644 
13645  } // if (left_sub_node_pt == right_sub_node_pt)
13646  else
13647  {
13648  // No need to create two boundaries, create only one with the
13649  // sub-list of nodes
13650 
13651  // Add the sub-list of nodes to the vector of lists of nodes
13652  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13653  // Add the sub-vector of elements to the vector of boundary
13654  // elements
13655  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13656  // Add the sub-vector of face indexes to the vector of face
13657  // indexes
13658  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13659 
13660  // Set the connection flags, change them by the proper connection
13661  // flag
13662 
13663  // The left connection flag
13664 
13665  // Connected with nothing but required to stop adding nodes
13666  if (input_connect_to_the_left == -3)
13667  {
13668  // Set to connected to nothing
13669  output_connect_to_the_left.push_back(-1);
13670  }
13671  // Connected with itself
13672  else if (input_connect_to_the_left == -2)
13673  {
13674  // Set connected to the next shared polyline id
13675  output_connect_to_the_left.push_back(tmp_shd_bnd_id + 1);
13676  }
13677  else
13678  {
13679  // Any other value keep it
13680  output_connect_to_the_left.push_back(input_connect_to_the_left);
13681  }
13682 
13683  // The right connection flag
13684 
13685  // Set connected to the next shared polyline id
13686  output_connect_to_the_right.push_back(tmp_shd_bnd_id + 1);
13687 
13688  // Increase the shared boundary id by one
13689  tmp_shd_bnd_id++;
13690 
13691  } // else if (left_sub_node_pt == right_sub_node_pt)
13692 
13693  // At least two sub-list of nodes were created
13694  if (n_sub_list > 1)
13695  {
13696  // ------------------------------------------------------------
13697  // Get the left and right node of the second sub-list of nodes
13698  left_sub_node_pt = tmp_sub_nodes[1].front();
13699  right_sub_node_pt = tmp_sub_nodes[1].back();
13700 
13701  // Check if the sub-list of nodes creates a loop (circle)
13702  if (left_sub_node_pt == right_sub_node_pt)
13703  {
13704  // We need to create two shared polylines and therefore increase
13705  // the shared boundary id by two
13706 
13707  // The first and second half of nodes
13708  std::list<Node*> first_half_node_pt;
13709  std::list<Node*> second_half_node_pt;
13710  // The first and second half of boundary elements
13711  Vector<FiniteElement*> first_half_ele_pt;
13712  Vector<FiniteElement*> second_half_ele_pt;
13713  // The first and second half of face indexes
13714  Vector<int> first_half_face_idx;
13715  Vector<int> second_half_face_idx;
13716 
13717  // Get the number of sub-nodes in the sub-list of nodes
13718  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13719 
13720  // The number of sub-nodes for the first half of the shared
13721  // boundary
13722  const unsigned n_sub_nodes_half =
13723  static_cast<unsigned>(n_sub_nodes / 2.0);
13724 
13725  // Copy as many sub-nodes for the first half of the sub-polyline
13726 
13727  // Iterator to loop over the nodes
13728  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13729 
13730  // Add the first node
13731  first_half_node_pt.push_back(*it_sub);
13732 
13733  // Skip the first node
13734  it_sub++;
13735 
13736  // Counter
13737  unsigned counter_nodes = 0;
13738  unsigned counter2 = 0;
13739 
13740  // Loop to copy the nodes
13741  for (; it_sub != tmp_sub_nodes[1].end(); it_sub++)
13742  {
13743  // Add the sub-node to the first half
13744  first_half_node_pt.push_back(*it_sub);
13745  // Add the boundary elements of the first half
13746  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13747  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2 + 1]);
13748  // Add the face indexes of the first half
13749  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13750  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2 + 1]);
13751 
13752  // Increase the counter of added nodes
13753  counter_nodes++;
13754 
13755  // Increase the other counter
13756  counter2 += 2;
13757 
13758  if (counter_nodes == n_sub_nodes_half)
13759  {
13760  // Stop adding to the first half of nodes
13761  break;
13762  }
13763 
13764  } // Copy the first half of nodes
13765 
13766  // The second half
13767 
13768  // Add the first node of the second half
13769  second_half_node_pt.push_back(*it_sub);
13770 
13771  // Skip the first node of the second half
13772  it_sub++;
13773 
13774  // Loop to copy the nodes
13775  for (; it_sub != tmp_sub_nodes[1].end(); it_sub++)
13776  {
13777  // Add the sub-node to the first half
13778  second_half_node_pt.push_back(*it_sub);
13779  // Add the boundary elements of the first half
13780  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13781  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2 + 1]);
13782  // Add the face indexes of the first half
13783  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13784  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2 + 1]);
13785 
13786  // Increase the other counter
13787  counter2 += 2;
13788 
13789  } // Copy the second half of nodes
13790 
13791  // Add the sub-list of nodes to the vector of lists of nodes
13792  output_sorted_nodes_pt.push_back(first_half_node_pt);
13793  output_sorted_nodes_pt.push_back(second_half_node_pt);
13794  // Add the sub-vector of elements to the vector of boundary
13795  // elements
13796  output_boundary_element_pt.push_back(first_half_ele_pt);
13797  output_boundary_element_pt.push_back(second_half_ele_pt);
13798  // Add the sub-vector of face indexes to the vector of face
13799  // indexes
13800  output_face_index_element.push_back(first_half_face_idx);
13801  output_face_index_element.push_back(second_half_face_idx);
13802 
13803  // Set the connection flags, change them by the proper
13804  // connection flag
13805 
13806  // --------------------------------------
13807  // Connections flags for the first half
13808 
13809  // The left connection flag
13810 
13811  // Connected to the previous boundary
13812  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13813 
13814  // The right connection flag
13815 
13816  // Set connected to nothing, this is the base node
13817  output_connect_to_the_right.push_back(-1);
13818 
13819  // Increase the shared boundary id
13820  tmp_shd_bnd_id++;
13821 
13822  // --------------------------------------
13823  // Connections flags for the second half
13824 
13825  // The left connection flag
13826 
13827  // Set connected to the previous boundary
13828  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13829 
13830  // The right connection flag
13831 
13832  // Are we in the last sub-list of nodes, if that is the case we
13833  // need to respect the flag assigned to the right
13834  if (n_sub_list == 2)
13835  {
13836  // Connected with nothing
13837  if (input_connect_to_the_right == -1)
13838  {
13839  // Set connected to the previous shared boundary
13840  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13841  }
13842  // Connected with the same boundary
13843  else if (input_connect_to_the_right == -2)
13844  {
13845  // Set connected to the previous shared boundary
13846  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13847  }
13848  // Connetted with nothing but stop adding nodes
13849  else if (input_connect_to_the_right == -3)
13850  {
13851  // Set connected to the previous shared boundary
13852  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13853  }
13854  else
13855  {
13856  // Any other value keep it
13857  output_connect_to_the_right.push_back(input_connect_to_the_right);
13858  }
13859 
13860  // Increase the shared boundary id
13861  tmp_shd_bnd_id++;
13862 
13863  } // if (n_sub_list == 2)
13864 #ifdef PARANOID
13865  else
13866  {
13867  std::stringstream error_message;
13868  error_message
13869  << "The second sub-list of nodes creates a loop but this is not\n"
13870  << "the last list of sub-nodes.\n"
13871  << "This configuration is not supported\n";
13872  throw OomphLibError(
13873  error_message.str(),
13874  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13875  OOMPH_EXCEPTION_LOCATION);
13876  }
13877 #endif
13878 
13879  } // if (left_sub_node_pt == right_sub_node_pt)
13880  else
13881  {
13882  // No need to create two boundaries, create only one with the
13883  // sub-list of nodes
13884 
13885  // Add the sub-list of nodes to the vector of lists of nodes
13886  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13887  // Add the sub-vector of elements to the vector of boundary
13888  // elements
13889  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13890  // Add the sub-vector of face indexes to the vector of face
13891  // indexes
13892  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13893 
13894  // Set the connection flags, change them by the proper connection
13895  // flag
13896 
13897  // The left connection flag
13898 
13899  // Set connected to the previous shared boundary id
13900  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13901 
13902  // The right connection flag
13903 
13904  // Are we in the last sub-list of nodes, if that is the case we
13905  // need to respect the flag assigned to the right
13906  if (n_sub_list == 2)
13907  {
13908  // Connected with nothing but required to stop adding nodes
13909  if (input_connect_to_the_right == -3)
13910  {
13911  // Set to connected to nothing
13912  output_connect_to_the_right.push_back(-1);
13913  }
13914 #ifdef PARANOID
13915  // Connected with itself
13916  else if (input_connect_to_the_right == -2)
13917  {
13918  std::stringstream error_message;
13919  error_message
13920  << "The connection flag to the right ("
13921  << input_connect_to_the_right << ") indicates a connection\n"
13922  << "with the same polyline.\n However, the second sub-list of\n"
13923  << "nodes was found not making a loop so no connection with\n"
13924  << "itself should be marked\n\n";
13925  throw OomphLibError(
13926  error_message.str(),
13927  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13928  OOMPH_EXCEPTION_LOCATION);
13929  }
13930 #endif
13931  else
13932  {
13933  // Any other value keep it
13934  output_connect_to_the_right.push_back(input_connect_to_the_right);
13935  }
13936  } // if (n_sub_list == 2)
13937  else
13938  {
13939  // Set connected to the next shared boundary id
13940  output_connect_to_the_right.push_back(tmp_shd_bnd_id + 1);
13941  } // else if (n_sub_list == 2)
13942 
13943  // Increase the shared boundary id by one
13944  tmp_shd_bnd_id++;
13945 
13946  } // if (left_sub_node_pt == right_sub_node_pt)
13947 
13948  } // if (n_sub_list > 1)
13949 
13950  // Three sub-list of nodes were created
13951  if (n_sub_list > 2)
13952  {
13953  // ------------------------------------------------------------
13954  // Get the left and right node of the third sub-list of nodes
13955  left_sub_node_pt = tmp_sub_nodes[2].front();
13956  right_sub_node_pt = tmp_sub_nodes[2].back();
13957 
13958  // Check if the sub-list of nodes creates a loop (circle)
13959  if (left_sub_node_pt == right_sub_node_pt)
13960  {
13961  // We need to create two shared polylines and therefore increase
13962  // the shared boundary id by two
13963 
13964  // The first and second half of nodes
13965  std::list<Node*> first_half_node_pt;
13966  std::list<Node*> second_half_node_pt;
13967  // The first and second half of boundary elements
13968  Vector<FiniteElement*> first_half_ele_pt;
13969  Vector<FiniteElement*> second_half_ele_pt;
13970  // The first and second half of face indexes
13971  Vector<int> first_half_face_idx;
13972  Vector<int> second_half_face_idx;
13973 
13974  // Get the number of sub-nodes in the sub-list of nodes
13975  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13976 
13977  // The number of sub-nodes for the first half of the shared
13978  // boundary
13979  const unsigned n_sub_nodes_half =
13980  static_cast<unsigned>(n_sub_nodes / 2.0);
13981 
13982  // Copy as many sub-nodes for the first half of the sub-polyline
13983 
13984  // Iterator to loop over the nodes
13985  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13986 
13987  // Add the first node
13988  first_half_node_pt.push_back(*it_sub);
13989 
13990  // Skip the first node
13991  it_sub++;
13992 
13993  // Counter
13994  unsigned counter_nodes = 0;
13995  unsigned counter2 = 0;
13996 
13997  // Loop to copy the nodes
13998  for (; it_sub != tmp_sub_nodes[2].end(); it_sub++)
13999  {
14000  // Add the sub-node to the first half
14001  first_half_node_pt.push_back(*it_sub);
14002  // Add the boundary elements of the first half
14003  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
14004  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2 + 1]);
14005  // Add the face indexes of the first half
14006  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
14007  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2 + 1]);
14008 
14009  // Increase the counter of added nodes
14010  counter_nodes++;
14011 
14012  // Increase the other counter
14013  counter2 += 2;
14014 
14015  if (counter_nodes == n_sub_nodes_half)
14016  {
14017  // Stop adding to the first half of nodes
14018  break;
14019  }
14020 
14021  } // Copy the first half of nodes
14022 
14023  // The second half
14024 
14025  // Add the first node of the second half
14026  second_half_node_pt.push_back(*it_sub);
14027 
14028  // Skip the first node of the second half
14029  it_sub++;
14030 
14031  // Loop to copy the nodes
14032  for (; it_sub != tmp_sub_nodes[2].end(); it_sub++)
14033  {
14034  // Add the sub-node to the first half
14035  second_half_node_pt.push_back(*it_sub);
14036  // Add the boundary elements of the first half
14037  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
14038  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2 + 1]);
14039  // Add the face indexes of the first half
14040  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
14041  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2 + 1]);
14042 
14043  // Increase the other counter
14044  counter2 += 2;
14045 
14046  } // Copy the second half of nodes
14047 
14048  // Add the sub-list of nodes to the vector of lists of nodes
14049  output_sorted_nodes_pt.push_back(first_half_node_pt);
14050  output_sorted_nodes_pt.push_back(second_half_node_pt);
14051  // Add the sub-vector of elements to the vector of boundary
14052  // elements
14053  output_boundary_element_pt.push_back(first_half_ele_pt);
14054  output_boundary_element_pt.push_back(second_half_ele_pt);
14055  // Add the sub-vector of face indexes to the vector of face
14056  // indexes
14057  output_face_index_element.push_back(first_half_face_idx);
14058  output_face_index_element.push_back(second_half_face_idx);
14059 
14060  // --------------------------------------
14061  // Connections flags for the first half
14062 
14063  // The left connection flag
14064 
14065  // Connected to the previous shared boundary
14066  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14067 
14068  // The right connection flag
14069 
14070  // Set connected to nothing, this is the base node
14071  output_connect_to_the_right.push_back(-1);
14072 
14073  // Increase the shared boundary id
14074  tmp_shd_bnd_id++;
14075 
14076  // --------------------------------------
14077  // Connections flags for the second half
14078 
14079  // The left connection flag
14080 
14081  // Set connected to the previous boundary
14082  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14083 
14084  // The right connection flag
14085 
14086  if (input_connect_to_the_right == -3)
14087  {
14088  // Set connected to the previous shared boundary id
14089  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14090  }
14091  else if (input_connect_to_the_right == -2)
14092  {
14093  // Set connected to the previous shared boundary id
14094  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14095  }
14096  else if (input_connect_to_the_right == -1)
14097  {
14098  // Set connected to the previous shared boundary id
14099  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14100  }
14101  else
14102  {
14103  // Any other value keep it
14104  output_connect_to_the_right.push_back(input_connect_to_the_right);
14105  }
14106 
14107  // Increase the shared boundary id
14108  tmp_shd_bnd_id++;
14109 
14110  } // if (left_sub_node_pt == right_sub_node_pt)
14111  else
14112  {
14113  // No need to create two boundaries, create only one with the
14114  // sub-list of nodes
14115 
14116  // Add the sub-list of nodes to the vector of lists of nodes
14117  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
14118  // Add the sub-vector of elements to the vector of boundary
14119  // elements
14120  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
14121  // Add the sub-vector of face indexes to the vector of face
14122  // indexes
14123  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
14124 
14125  // Set the connection flags, change them by the proper
14126  // connection flag
14127 
14128  // The left connection flag
14129 
14130  // Set connected to the previous shared boundary id
14131  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14132 
14133  // The right connection flag
14134 
14135  // Connected with nothing but required to stop adding nodes
14136  if (input_connect_to_the_right == -3)
14137  {
14138  std::stringstream error_message;
14139  error_message
14140  << "The connection flag to the right ("
14141  << input_connect_to_the_right << ") indicates 'no connection and\n"
14142  << "stop adding nodes'.\n However, the thrid sub-list of\n"
14143  << "nodes must have a connection to the right with the same\n"
14144  << "shared polyline or with any other polyline\n\n";
14145  throw OomphLibError(
14146  error_message.str(),
14147  "TriangleMesh::break_loops_on_shared_polyline_helper()",
14148  OOMPH_EXCEPTION_LOCATION);
14149  }
14150  else if (input_connect_to_the_right == -1)
14151  {
14152  std::stringstream error_message;
14153  error_message
14154  << "The connection flag to the right ("
14155  << input_connect_to_the_right << ") indicates 'no connection.\n"
14156  << "However, the thrid sub-list of nodes must have a connection\n"
14157  << "to the right with the same shared polyline or with any other\n"
14158  << "polyline\n\n";
14159  throw OomphLibError(
14160  error_message.str(),
14161  "TriangleMesh::break_loops_on_shared_polyline_helper()",
14162  OOMPH_EXCEPTION_LOCATION);
14163  }
14164  // Connected with itself
14165  else if (input_connect_to_the_right == -2)
14166  {
14167  // Set connected to the previous shared boundary id
14168  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14169  }
14170  else
14171  {
14172  // Any other value keep it
14173  output_connect_to_the_right.push_back(input_connect_to_the_right);
14174  }
14175 
14176  // Increase the shared boundary id by one
14177  tmp_shd_bnd_id++;
14178 
14179  } // if (left_sub_node_pt == right_sub_node_pt)
14180 
14181  } // if (n_sub_list > 2)
14182  }
14183 
14184  // ======================================================================
14185  // \short Break any possible loop created by the sorted list of nodes
14186  // that is used to create a new shared polyline
14187  // ======================================================================
14188  template<class ELEMENT>
14191  const unsigned& initial_shd_bnd_id,
14192  std::list<Node*>& input_nodes,
14193  Vector<FiniteElement*>& input_boundary_element_pt,
14194  Vector<FiniteElement*>& input_boundary_face_element_pt,
14195  Vector<int>& input_face_index_element,
14196  const int& input_connect_to_the_left,
14197  const int& input_connect_to_the_right,
14198  Vector<std::list<Node*>>& output_sorted_nodes_pt,
14199  Vector<Vector<FiniteElement*>>& output_boundary_element_pt,
14200  Vector<Vector<FiniteElement*>>& output_boundary_face_element_pt,
14201  Vector<Vector<int>>& output_face_index_element,
14202  Vector<int>& output_connect_to_the_left,
14203  Vector<int>& output_connect_to_the_right)
14204  {
14205  // Get the left and right node of the current list of sorted nodes
14206  Node* left_node_pt = input_nodes.front();
14207  Node* right_node_pt = input_nodes.back();
14208 
14209  // Temporary storage for list of nodes, boundary elements, boundary
14210  // face elements and face element's indexes
14211  Vector<std::list<Node*>> tmp_sub_nodes;
14212  Vector<Vector<FiniteElement*>> tmp_sub_bnd_ele_pt;
14213  Vector<Vector<FiniteElement*>> tmp_sub_bnd_face_ele_pt;
14214  Vector<Vector<int>> tmp_sub_face_idx_ele;
14215 
14216  // Iterator for the list of input nodes
14217  std::list<Node*>::iterator it = input_nodes.begin();
14218 
14219  // Counter
14220  unsigned counter = 0;
14221 
14222  // Loop while not all nodes have been done
14223  while (it != input_nodes.end())
14224  {
14225  // Check if the current node is the final one
14226  it++;
14227  // Is the current node the final node?
14228  if (it == input_nodes.end())
14229  {
14230  // Break, add no more nodes
14231  break;
14232  }
14233  else
14234  {
14235  // Restore the iterator
14236  it--;
14237  }
14238 
14239  // Get a list of nonrepeated nodes
14240  std::list<Node*> sub_nodes;
14241  // The temporary vector of boundary elements associated with the
14242  // nodes
14243  Vector<FiniteElement*> sub_bnd_ele_pt;
14244  // The temporary vector of boundary face elements associated with
14245  // the nodes
14246  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14247  // The temporary vector of face indexes associated with the
14248  // boundary elements
14249  Vector<int> sub_face_idx_ele;
14250 
14251  // Add the current node to the list
14252  sub_nodes.push_back(*it);
14253 
14254  // Add nodes until found a repeated node (the left or right
14255  // node) or until reaching the end of the list of nodes
14256  do
14257  {
14258  // Go to the next node
14259  ++it;
14260 
14261  // Add the new node
14262  sub_nodes.push_back((*it));
14263 
14264  // Add the boundary elements
14265  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14266 
14267  // Add the boundary face elements
14268  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14269 
14270  // Add the face indexes
14271  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14272 
14273  // Increase the counter
14274  counter++;
14275 
14276  // Continue adding until reaching a repeated node or the end
14277  // of the list of nodes
14278  } while ((*it) != left_node_pt && (*it) != right_node_pt &&
14279  it != input_nodes.end());
14280 
14281  // Add the sub-set of nodes to the temporary storage
14282  tmp_sub_nodes.push_back(sub_nodes);
14283 
14284  // Add the boundary elements to the temporary storage
14285  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14286  // Add the boundary face elements to the temporary storage
14287  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14288  // Add the face indexes to the temporary storage
14289  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14290 
14291  } // while((*it) != input_nodes.end())
14292 
14293  // --------------------------------------------------
14294  // Now create as many shared boundaries as required
14295 
14296  // Get the number of sub-list of nodes created
14297  const unsigned n_sub_list = tmp_sub_nodes.size();
14298 
14299 #ifdef PARANOID
14300  if (n_sub_list > 1)
14301  {
14302  std::stringstream error_message;
14303  error_message
14304  << "The number of sub-list of nodes created from the shared\n"
14305  << "polyline with loops was (" << n_sub_list << ").\n"
14306  << "We can only handle one list which may still contain loops\n"
14307  << "(or repeated nodes)\n";
14308  throw OomphLibError(
14309  error_message.str(),
14310  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14311  OOMPH_EXCEPTION_LOCATION);
14312  }
14313 #endif
14314 
14315  // If there is only one list it may be because there are no loops or
14316  // there is only one loop (a circle)
14317  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14318  {
14319  // There are no loops, return just after filling the data
14320  // structures
14321 
14322  // This is the base case used most of the times
14323 
14324  // Set the vector of lists of nodes
14325  output_sorted_nodes_pt = tmp_sub_nodes;
14326  // Set the vector of boundary elements
14327  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14328  // Set the vector of boundary face elements
14329  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14330  // Set the vector of face indexes
14331  output_face_index_element = tmp_sub_face_idx_ele;
14332 
14333  // Set the connection flags, change them by the proper connection
14334  // flag
14335 
14336 #ifdef PARANOID
14337  if (input_connect_to_the_left == -2)
14338  {
14339  std::stringstream error_message;
14340  error_message
14341  << "The connection flag to the left (" << input_connect_to_the_left
14342  << ") indicates a connection\n"
14343  << "with the same polyline.\n However, only one sub-polyline was "
14344  << "found and no loops\nwere identified\n\n";
14345  throw OomphLibError(
14346  error_message.str(),
14347  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14348  OOMPH_EXCEPTION_LOCATION);
14349  }
14350 #endif
14351 
14352  // The left connection flag
14353  if (input_connect_to_the_left == -3)
14354  {
14355  output_connect_to_the_left.push_back(-1);
14356  }
14357  else
14358  {
14359  output_connect_to_the_left.push_back(input_connect_to_the_left);
14360  }
14361 
14362 #ifdef PARANOID
14363  if (input_connect_to_the_right == -2)
14364  {
14365  std::stringstream error_message;
14366  error_message
14367  << "The connection flag to the right (" << input_connect_to_the_right
14368  << ") indicates a connection\n"
14369  << "with the same polyline.\n However, only one sub-polyline was "
14370  << "found and no loops\nwere identified\n\n";
14371  throw OomphLibError(
14372  error_message.str(),
14373  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14374  OOMPH_EXCEPTION_LOCATION);
14375  }
14376 #endif
14377 
14378  // The right connection flag
14379  if (input_connect_to_the_right == -3)
14380  {
14381  output_connect_to_the_right.push_back(-1);
14382  }
14383  else
14384  {
14385  output_connect_to_the_right.push_back(input_connect_to_the_right);
14386  }
14387 
14388  // Return immediately
14389  return;
14390  }
14391 
14392  // The temporary storage for the shared boundary id
14393  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14394 
14395  // -----------------------------------------------------------------
14396  // Check all the sub-list of nodes and create two shared boundaries
14397  // from those that make a loop (circle)
14398 
14399  // -----------------------------------------------------------
14400  // Get the left and right node of the first sub-list of nodes
14401  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14402  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14403 
14404  // Check if the sub-list of nodes creates a loop (circle)
14405  if (left_sub_node_pt == right_sub_node_pt)
14406  {
14407  // We need to create two shared polylines and therefore increase
14408  // the shared boundary id by two
14409 
14410  // The first and second half of nodes
14411  std::list<Node*> first_half_node_pt;
14412  std::list<Node*> second_half_node_pt;
14413  // The first and second half of boundary elements
14414  Vector<FiniteElement*> first_half_ele_pt;
14415  Vector<FiniteElement*> second_half_ele_pt;
14416  // The first and second half of boundary face elements
14417  Vector<FiniteElement*> first_half_ele_face_pt;
14418  Vector<FiniteElement*> second_half_ele_face_pt;
14419  // The first and second half of face indexes
14420  Vector<int> first_half_face_idx;
14421  Vector<int> second_half_face_idx;
14422 
14423  // Get the number of sub-nodes in the sub-list of nodes
14424  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14425 
14426  // The number of sub-nodes for the first half of the shared
14427  // boundary
14428  const unsigned n_sub_nodes_half =
14429  static_cast<unsigned>(n_sub_nodes / 2.0);
14430 
14431  // Copy as many sub-nodes for the first half of the sub-polyline
14432 
14433  // Iterator to loop over the nodes
14434  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14435 
14436  // Add the first node
14437  first_half_node_pt.push_back(*it_sub);
14438 
14439  // Skip the first node
14440  it_sub++;
14441 
14442  // Counter
14443  unsigned counter_nodes = 0;
14444  unsigned counter2 = 0;
14445 
14446  // Loop to copy the nodes
14447  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
14448  {
14449  // Add the sub-node to the first half
14450  first_half_node_pt.push_back(*it_sub);
14451 
14452  // Add the boundary elements of the first half
14453  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14454  // Add the boundary face elements of the first half
14455  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14456  // Add the face indexes of the first half
14457  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14458 
14459  // Increase the counter of added nodes
14460  counter_nodes++;
14461 
14462  // Increase the other counter (of the elements/face)
14463  counter2++;
14464 
14465  if (counter_nodes == n_sub_nodes_half)
14466  {
14467  // Stop adding to the first half of nodes
14468  break;
14469  }
14470 
14471  } // Copy the first half of nodes
14472 
14473  // The second half
14474 
14475  // Add the first node of the second half
14476  second_half_node_pt.push_back(*it_sub);
14477 
14478  // Skip the first node of the second half
14479  it_sub++;
14480 
14481  // Loop to copy the nodes
14482  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
14483  {
14484  // Add the sub-node to the first half
14485  second_half_node_pt.push_back(*it_sub);
14486 
14487  // Add the boundary elements of the first half
14488  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14489  // Add the boundary face elements of the first half
14490  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14491  // Add the face indexes of the first half
14492  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14493 
14494  // Increase the other counter
14495  counter2++;
14496 
14497  } // Copy the second half of nodes
14498 
14499  // Add the sub-list of nodes to the vector of lists of nodes
14500  output_sorted_nodes_pt.push_back(first_half_node_pt);
14501  output_sorted_nodes_pt.push_back(second_half_node_pt);
14502  // Add the sub-vector of elements to the vector of boundary
14503  // elements
14504  output_boundary_element_pt.push_back(first_half_ele_pt);
14505  output_boundary_element_pt.push_back(second_half_ele_pt);
14506  // Add the sub-vector of face elements to the vector of boundary
14507  // elements
14508  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14509  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14510  // Add the sub-vector of face indexes to the vector of face
14511  // indexes
14512  output_face_index_element.push_back(first_half_face_idx);
14513  output_face_index_element.push_back(second_half_face_idx);
14514 
14515  // Set the connection flags, change them by the proper connection
14516  // flag
14517 
14518  // ----------------------------------------------------------------
14519  // Connections flags for the first half
14520 
14521  // The left connection flag
14522 
14523  // Connected with nothing but required to stop adding nodes
14524  if (input_connect_to_the_left == -3)
14525  {
14526  // Set connected to nothing
14527  output_connect_to_the_left.push_back(-1);
14528  }
14529  // Connected with itself
14530  else if (input_connect_to_the_left == -2)
14531  {
14532  // Set connected to nothing, this is the base node
14533  output_connect_to_the_left.push_back(-1);
14534  }
14535  else
14536  {
14537  // Any other value keep it
14538  output_connect_to_the_left.push_back(input_connect_to_the_left);
14539  }
14540 
14541  // The right connection flag
14542 
14543  // Set connected to nothing, this is the base node
14544  output_connect_to_the_right.push_back(-1);
14545 
14546  // Increase the shared boundary id
14547  tmp_shd_bnd_id++;
14548 
14549  // ----------------------------------------------------------------
14550  // Connections flags for the second half
14551 
14552  // The left connection flag
14553 
14554  // Set connected to the previous boundary
14555  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14556 
14557  // The right connection flag
14558 
14559  // Are we in the last sub-list of nodes, if that is the case we
14560  // need to respect the flag assigned to the right
14561  if (n_sub_list == 1)
14562  {
14563  if (input_connect_to_the_right == -3)
14564  {
14565  // Set connected to the previous shared boundary id
14566  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14567  }
14568  else if (input_connect_to_the_right == -2)
14569  {
14570  // Set connected to the previous shared boundary id
14571  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14572  }
14573  else if (input_connect_to_the_right == -1)
14574  {
14575  // Set connected to the previous shared boundary id
14576  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14577  }
14578  else
14579  {
14580  // Any other value keep it
14581  output_connect_to_the_right.push_back(input_connect_to_the_right);
14582  }
14583  } // if (n_sub_list == 1)
14584  else
14585  {
14586  // Set connected to the previous shared boundary id
14587  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14588  }
14589 
14590  // Increase the shared boundary id
14591  tmp_shd_bnd_id++;
14592 
14593  } // if (left_sub_node_pt == right_sub_node_pt)
14594 #ifdef PARANOID
14595  else
14596  {
14597  std::stringstream error_message;
14598  error_message
14599  << "The initial and final node in the current shared polyline are not\n"
14600  << "the same and the number of sublists is (" << n_sub_list << ").\n"
14601  << "We can not handle more than one sublist in the method to break\n"
14602  << "loops at the load balance stage\n\n";
14603  throw OomphLibError(
14604  error_message.str(),
14605  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14606  OOMPH_EXCEPTION_LOCATION);
14607  }
14608 #endif
14609  }
14610 
14611  // ======================================================================
14612  // \short Create the shared polyline and fill the data structured
14613  // that keep all the information associated with the creationg of the
14614  // shared boundary
14615  // ======================================================================
14616  template<class ELEMENT>
14618  const unsigned& my_rank,
14619  const unsigned& shd_bnd_id,
14620  const unsigned& iproc,
14621  const unsigned& jproc,
14622  std::list<Node*>& sorted_nodes,
14623  const int& root_edge_bnd_id,
14624  Vector<FiniteElement*>& bulk_bnd_ele_pt,
14625  Vector<int>& face_index_ele,
14626  Vector<Vector<TriangleMeshPolyLine*>>& unsorted_polylines_pt,
14627  const int& connect_to_the_left_flag,
14628  const int& connect_to_the_right_flag)
14629  {
14630  // ----------------------------------------------------------------
14631  // Associate the shared boundary with the respective processors
14632  // ----------------------------------------------------------------
14633 
14634  // Setup the global look-up scheme, where all processors know the
14635  // associations of others processors and the shared boundaries they
14636  // created
14637 
14638  // Set up the boundary shared by "iproc" with "jproc" processor
14639  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14640 
14641  // Set up the boundary shared by "jproc" with "iproc" processor
14642  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14643 
14644  // Specify the processors involved on the creation of the shared
14645  // boundary
14646  Vector<unsigned> processors(2);
14647  processors[0] = iproc;
14648  processors[1] = jproc;
14649  Shared_boundary_from_processors[shd_bnd_id] = processors;
14650 
14651  // ----------------------------------------------------------------
14652  // If one of the processor associated with the shared boundary is
14653  // the current processor then it needs to create a polyline from the
14654  // input sorted nodes, other processors can skip this part
14655  if (iproc == my_rank || jproc == my_rank)
14656  {
14657  // ------------------------------------------------------------
14658  // Create a vertices representation from the sorted nodes list
14659  // ------------------------------------------------------------
14660 
14661  // Get the number of nodes on the list
14662  const unsigned n_nodes = sorted_nodes.size();
14663  // The vector to store the vertices (assign space)
14664  Vector<Vector<double>> vertices(n_nodes);
14665 
14666  // Copy the vertices from the nodes
14667  unsigned counter = 0;
14668 
14669  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14670  it != sorted_nodes.end();
14671  it++)
14672  {
14673  vertices[counter].resize(2);
14674  vertices[counter][0] = (*it)->x(0);
14675  vertices[counter][1] = (*it)->x(1);
14676  counter++;
14677  }
14678 
14679  // ---------------------------------------------
14680  // Create the polyline from the input vertices
14681  // ---------------------------------------------
14682  TriangleMeshPolyLine* polyline_pt =
14683  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14684 
14685  // ---------------------------------------------
14686  // Establish the internal boundary information
14687  // ---------------------------------------------
14688 
14689  // Check if the shared boundary is overlapping (or is part) of an
14690  // internal boundary
14691  if (root_edge_bnd_id != -1)
14692  {
14693  // If the shared boundary is part of an internal boundary then
14694  // mark the shared boundary
14695  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14696  static_cast<unsigned>(root_edge_bnd_id);
14697  } // if (root_edge_bnd_id != -1)
14698 
14699  // ---------------------------------------------
14700  // Store the boundary elements and face indexes
14701  // ---------------------------------------------
14702 
14703  // Store the shared boundary elements
14704  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14705 #ifdef PARANOID
14706  // Check that the number of shared boundy elements is the same as
14707  // the number of face indexes
14708  const unsigned n_face_index = face_index_ele.size();
14709  if (n_shared_boundary_elements != n_face_index)
14710  {
14711  std::ostringstream error_message;
14712  error_message
14713  << "The number of shared boundary elements is different from the\n"
14714  << "number of face indexes associated to the shared boundary\n"
14715  << "elements\n"
14716  << "Number of shared boundary elements: ("
14717  << n_shared_boundary_elements << ")\n"
14718  << "Number of face indexes: (" << n_face_index << ")\n\n";
14719  throw OomphLibError(error_message.str(),
14720  "TriangleMesh::create_shared_polyline()",
14721  OOMPH_EXCEPTION_LOCATION);
14722  } // if (n_shared_boundary_elements != n_face_index)
14723 #endif
14724 
14725  // Add the shared boundary elements and their respective face
14726  // indexes to their permanent containers
14727  for (unsigned i = 0; i < n_shared_boundary_elements; i++)
14728  {
14729  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14730  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14731  } // for (i < nshared_boundary_elements)
14732 
14733  // Store the shared boundary nodes
14734  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14735  it != sorted_nodes.end();
14736  it++)
14737  {
14738  add_shared_boundary_node(shd_bnd_id, (*it));
14739  } // for (it != sorted_nodes.end())
14740 
14741  // ----------------------------------------------------------
14742  // Create additional look-up schemes for the shared boundary
14743  // ----------------------------------------------------------
14744 
14745  // Updates bnd_id <---> curve section map
14746  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14747 
14748  // Check the size of the unsorted_polylines_pt structure. This
14749  // will have n_procs = 1 when it was called from the
14750  // create_new_shared_boundaries() methods
14751  const unsigned n_procs = unsorted_polylines_pt.size();
14752  if (n_procs > 1)
14753  {
14754  // Add the new created polyline to the list of unsorted
14755  // polylines
14756  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14757 
14758  // ... do this on both processors involved in the creation of
14759  // the shared boundary
14760  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14761  }
14762  else
14763  {
14764  // Add the new created polyline to the list of unsorted
14765  // polylines
14766  unsorted_polylines_pt[0].push_back(polyline_pt);
14767  }
14768 
14769  // Mark the polyline for deletion (when calling destructor)
14770  this->Free_curve_section_pt.insert(polyline_pt);
14771 
14772  // ----------------------------
14773  // Set connection information
14774  // ----------------------------
14775 
14776  // Check that the flags are correct, no connection or the boundary
14777  // id of the boundary to connect
14778 #ifdef PARANOID
14779  // Is the shared polyline not connected to the left
14780  if (connect_to_the_left_flag < 0)
14781  {
14782  // If not connected then should be specified by -1
14783  if (connect_to_the_left_flag != -1)
14784  {
14785  std::ostringstream error_message;
14786  error_message
14787  << "The only accepted values for the connection flags are:\n"
14788  << "POSITIVE values or -1, any other value is rejected, please\n"
14789  << "check that you previously called the methods to deal with\n"
14790  << "other flag values\n"
14791  << "The current flag value for connection to the left is: ("
14792  << connect_to_the_left_flag << ")\n\n";
14793  throw OomphLibError(error_message.str(),
14794  "TriangleMesh::create_shared_polyline()",
14795  OOMPH_EXCEPTION_LOCATION);
14796  } // if (connect_to_the_left_flag != -1)
14797  } // if (connect_to_the_left_flag < 0)
14798 
14799  // Is the shared polyline not connected to the right
14800  if (connect_to_the_right_flag < 0)
14801  {
14802  // If not connected then should be specified by -1
14803  if (connect_to_the_right_flag != -1)
14804  {
14805  std::ostringstream error_message;
14806  error_message
14807  << "The only accepted values for the connection flags are:\n"
14808  << "POSITIVE values or -1, any other value is rejected, please\n"
14809  << "check that you previously called the methods to deal with\n"
14810  << "other flag values\n"
14811  << "The current flag value for connection to the right is: ("
14812  << connect_to_the_right_flag << ")\n\n";
14813  throw OomphLibError(error_message.str(),
14814  "TriangleMesh::create_shared_polyline()",
14815  OOMPH_EXCEPTION_LOCATION);
14816  } // if (connect_to_the_right_flag != -1)
14817  } // if (connect_to_the_right_flag < 0)
14818 #endif
14819 
14820  // Set the connection to the left
14821  if (connect_to_the_left_flag != -1)
14822  {
14823  // Get the unsigned version of the boundary id to the left
14824  const unsigned bnd_id_connection_to_the_left =
14825  static_cast<unsigned>(connect_to_the_left_flag);
14826  // Set the initial vertex as connected
14827  polyline_pt->set_initial_vertex_connected();
14828  // Set the initial vertex connected boundary id
14829  polyline_pt->initial_vertex_connected_bnd_id() =
14830  bnd_id_connection_to_the_left;
14831  // Set the chunk number to zero
14832  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14833 
14834  } // if (connect_to_the_left_flag != -1)
14835 
14836  // Set the connection to the right
14837  if (connect_to_the_right_flag != -1)
14838  {
14839  // Get the unsigned version of the boundary id to the right
14840  const unsigned bnd_id_connection_to_the_right =
14841  static_cast<unsigned>(connect_to_the_right_flag);
14842  // Set the final vertex as connected
14843  polyline_pt->set_final_vertex_connected();
14844  // Set the final vertex connected boundary id
14845  polyline_pt->final_vertex_connected_bnd_id() =
14846  bnd_id_connection_to_the_right;
14847  // Set the chunk number to zero
14848  polyline_pt->final_vertex_connected_n_chunk() = 0;
14849 
14850  } // if (connect_to_the_right_flag != -1)
14851 
14852  } // if (iproc == my_rank || jproc == my_rank)
14853  }
14854 
14855  //======================================================================
14856  /// \short Reset the boundary elements info. after load balance have
14857  /// taken place
14858  //======================================================================
14859  template<class ELEMENT>
14861  Vector<unsigned>& ntmp_boundary_elements,
14862  Vector<Vector<unsigned>>& ntmp_boundary_elements_in_region,
14863  Vector<FiniteElement*>& deleted_elements)
14864  {
14865  // Get the number of boundaries
14866  const unsigned nbound = this->nboundary();
14867 
14868  // Are there regions?
14869  const unsigned n_regions = this->nregion();
14870 
14871  // Loop over the boundaries
14872  for (unsigned b = 0; b < nbound; b++)
14873  {
14874  // Get the boundary elements and back them up
14875  // -----------------------------------------------------------------
14876  // Get the number of boundary elements (mixed with the old and new)
14877  const unsigned nbound_ele = this->nboundary_element(b);
14878  // Back-up the boundary elements
14879  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14880  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14881  for (unsigned e = 0; e < nbound_ele; e++)
14882  {
14883  // Get the old boundary element
14884  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14885  // Get the old face index
14886  backed_up_face_index_at_boundary[e] =
14887  this->face_index_at_boundary(b, e);
14888  } // for (n < nold_boundary_elements)
14889 
14890  // Back up the elements in boundary for each region
14891  Vector<Vector<FiniteElement*>> backed_up_boundary_region_element_pt(
14892  n_regions);
14893  Vector<Vector<int>> backed_up_face_index_at_boundary_region(n_regions);
14894 
14895  // Loop over the regions and back up the boundary elements in
14896  // regions
14897  for (unsigned ir = 0; ir < n_regions; ir++)
14898  {
14899  // Get the region id
14900  const unsigned region_id =
14901  static_cast<unsigned>(this->region_attribute(ir));
14902  // Get the number of boundary region elements (mixed old and new)
14903  const unsigned nbnd_region_ele =
14904  this->nboundary_element_in_region(b, region_id);
14905 
14906  // Loop over the elements in the region
14907  for (unsigned e = 0; e < nbnd_region_ele; e++)
14908  {
14909  // Get the old boundary region element
14910  backed_up_boundary_region_element_pt[ir][e] =
14911  this->boundary_element_in_region_pt(b, region_id, e);
14912 
14913  // Get the old face index
14914  backed_up_face_index_at_boundary_region[ir][e] =
14915  this->face_index_at_boundary_in_region(b, region_id, e);
14916  } // for (e < nbnd_region_ele)
14917 
14918  } // for (ir < n_regions)
14919 
14920  // Clean all previous storages
14921  this->Boundary_element_pt[b].clear();
14922  this->Face_index_at_boundary[b].clear();
14923  if (n_regions > 0)
14924  {
14925  this->Boundary_region_element_pt[b].clear();
14926  this->Face_index_region_at_boundary[b].clear();
14927  }
14928 
14929  // -------------------------------------------------------------------
14930  // Now copy only the elements that are still alive, from those before
14931  // the re-establishment of halo and haloed elements
14932  // -------------------------------------------------------------------
14933  // Start with the boundary elements
14934  // Get the old number of boundary elements
14935  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14936  // Loop over the boundary elements and check those still alive
14937  for (unsigned e = 0; e < nold_bnd_ele; e++)
14938  {
14939  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14940  // Include only those elements still alive
14941  Vector<FiniteElement*>::iterator it = std::find(
14942  deleted_elements.begin(), deleted_elements.end(), tmp_ele_pt);
14943  // Only copy thoes elements not found on the deleted elements
14944  // container
14945  if (it == deleted_elements.end())
14946  {
14947  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14948  this->Boundary_element_pt[b].push_back(add_ele_pt);
14949  const int face_index = backed_up_face_index_at_boundary[e];
14950  this->Face_index_at_boundary[b].push_back(face_index);
14951  } // if (tmp_ele_pt != 0)
14952 
14953  } // for (n < nold_bnd_ele)
14954 
14955  // ... continue with the boundary elements in specific regions
14956 
14957  // Loop over the regions
14958  for (unsigned ir = 0; ir < n_regions; ir++)
14959  {
14960  // Get the region id
14961  const unsigned region_id =
14962  static_cast<unsigned>(this->region_attribute(ir));
14963 
14964  // Get the old number of boundary elements in region
14965  const unsigned nold_bnd_region_ele =
14966  ntmp_boundary_elements_in_region[b][ir];
14967 
14968  // Loop over the boundary region elements and check those still
14969  // alive
14970  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14971  {
14972  // Get the element
14973  FiniteElement* tmp_ele_pt =
14974  backed_up_boundary_region_element_pt[ir][e];
14975  // Include only those elements still alive
14976  Vector<FiniteElement*>::iterator it = std::find(
14977  deleted_elements.begin(), deleted_elements.end(), tmp_ele_pt);
14978  // Only copy those elements not found on the deleted elements
14979  // container
14980  if (it == deleted_elements.end())
14981  {
14982  FiniteElement* add_ele_pt =
14983  backed_up_boundary_region_element_pt[ir][e];
14984  this->Boundary_region_element_pt[b][region_id].push_back(
14985  add_ele_pt);
14986  const int face_index =
14987  backed_up_face_index_at_boundary_region[ir][e];
14988  this->Face_index_region_at_boundary[b][region_id].push_back(
14989  face_index);
14990  } // if (tmp_ele_pt != 0)
14991 
14992  } // for (n < nbound_ele)
14993 
14994  } // for (ir < n_regions)
14995 
14996  // ----------------------------------------------------------------
14997  // Now copy all those elements created after the re-establishment
14998  // of halo and haloed elements
14999  // ----------------------------------------------------------------
15000  // Loop over the boundary elements
15001  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
15002  {
15003  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
15004  this->Boundary_element_pt[b].push_back(add_ele_pt);
15005  const int face_index = backed_up_face_index_at_boundary[e];
15006  this->Face_index_at_boundary[b].push_back(face_index);
15007  } // for (e < nbound_ele)
15008 
15009  // Now add the boundary elements in regions
15010 
15011  // Loop over the regions
15012  for (unsigned ir = 0; ir < n_regions; ir++)
15013  {
15014  // Get the region id
15015  const unsigned region_id =
15016  static_cast<unsigned>(this->region_attribute(ir));
15017 
15018  // Get the old number of boundary elements in region
15019  const unsigned nold_bnd_region_ele =
15020  ntmp_boundary_elements_in_region[b][ir];
15021 
15022  // Get the new number of boundary elements in region
15023  const unsigned nbnd_region_ele =
15024  this->nboundary_element_in_region(b, region_id);
15025 
15026  // Loop over the boundary region elements and check those still
15027  // alive
15028  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
15029  {
15030  FiniteElement* add_ele_pt =
15031  backed_up_boundary_region_element_pt[ir][e];
15032  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
15033  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
15034  this->Face_index_region_at_boundary[b][region_id].push_back(
15035  face_index);
15036  } // for (e < nbnd_region_ele)
15037 
15038  } // for (ir < n_regions)
15039 
15040  } // for (b < nbound)
15041 
15042  // Lookup scheme has now been setup yet
15043  Lookup_for_elements_next_boundary_is_setup = true;
15044  }
15045 
15046 #endif // OOMPH_HAS_MPI
15047 
15048 #ifdef OOMPH_HAS_TRIANGLE_LIB
15049 
15050  //========================================================================
15051  /// Build a new TriangulateIO object based on target areas specified
15052  //========================================================================
15053  template<class ELEMENT>
15055  TriangulateIO& triangulate_io,
15056  const Vector<double>& target_area,
15057  struct TriangulateIO& triangle_refine)
15058  {
15059  // Initialize
15060  TriangleHelper::initialise_triangulateio(triangle_refine);
15061 
15062  // Store the global number of vertices and segments
15063  // in the list
15064  unsigned n_points = triangulate_io.numberofpoints;
15065  triangle_refine.numberofpoints = n_points;
15066 
15067  unsigned n_segments = triangulate_io.numberofsegments;
15068  triangle_refine.numberofsegments = n_segments;
15069 
15070  // Initialization of the TriangulateIO objects to store the values
15071  triangle_refine.pointlist =
15072  (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
15073  triangle_refine.pointmarkerlist =
15074  (int*)malloc(triangulate_io.numberofpoints * sizeof(int));
15075  triangle_refine.segmentlist =
15076  (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
15077  triangle_refine.segmentmarkerlist =
15078  (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
15079 
15080  // Storing the point's coordinates in the list
15081  // and in two vectors with x and y coordinates
15082  Vector<double> x_coord(n_points);
15083  Vector<double> y_coord(n_points);
15084 
15085  for (unsigned count_point = 0; count_point < n_points * 2; count_point++)
15086  {
15087  triangle_refine.pointlist[count_point] =
15088  triangulate_io.pointlist[count_point];
15089 
15090  // Even vaules represent the x coordinate
15091  // Odd values represent the y coordinate
15092  if (count_point % 2 == 0)
15093  {
15094  x_coord[count_point / 2] = triangulate_io.pointlist[count_point];
15095  }
15096  else
15097  {
15098  y_coord[(count_point - 1) / 2] = triangulate_io.pointlist[count_point];
15099  }
15100  }
15101 
15102  // Store the point's markers in the list
15103  for (unsigned count_marker = 0; count_marker < n_points; count_marker++)
15104  {
15105  triangle_refine.pointmarkerlist[count_marker] =
15106  triangulate_io.pointmarkerlist[count_marker];
15107  }
15108 
15109  // Storing the segment's edges in the list
15110  for (unsigned count_seg = 0; count_seg < n_segments * 2; count_seg++)
15111  {
15112  triangle_refine.segmentlist[count_seg] =
15113  triangulate_io.segmentlist[count_seg];
15114  }
15115 
15116  // Store the segment's markers in the list
15117  for (unsigned count_markers = 0; count_markers < n_segments;
15118  count_markers++)
15119  {
15120  triangle_refine.segmentmarkerlist[count_markers] =
15121  triangulate_io.segmentmarkerlist[count_markers];
15122  }
15123 
15124  // Store the hole's center coordinates
15125  unsigned n_holes = triangulate_io.numberofholes;
15126  triangle_refine.numberofholes = n_holes;
15127 
15128  triangle_refine.holelist =
15129  (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
15130 
15131  // Loop over the holes to get centre coords
15132  for (unsigned count_hole = 0; count_hole < n_holes * 2; count_hole++)
15133  {
15134  triangle_refine.holelist[count_hole] =
15135  triangulate_io.holelist[count_hole];
15136  }
15137 
15138  // Store the triangles values
15139  unsigned n_triangles = triangulate_io.numberoftriangles;
15140  triangle_refine.numberoftriangles = n_triangles;
15141 
15142 #ifdef PARANOID
15143  if (n_triangles != target_area.size())
15144  {
15145  std::stringstream err;
15146  err << "Number of triangles in triangulate_io=" << n_triangles
15147  << " doesn't match\n"
15148  << "size of target area vector (" << target_area.size() << ")\n";
15149  throw OomphLibError(
15150  err.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15151  }
15152 #endif
15153 
15154  unsigned n_corners = triangulate_io.numberofcorners;
15155  triangle_refine.numberofcorners = n_corners;
15156 
15157  triangle_refine.trianglelist =
15158  (int*)malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
15159 
15160  // Store the triangle's corners in the list and get element sizes
15161  for (unsigned count_tri = 0; count_tri < n_triangles * 3; count_tri++)
15162  {
15163  triangle_refine.trianglelist[count_tri] =
15164  triangulate_io.trianglelist[count_tri];
15165  }
15166 
15167  // Store the triangle's area in the list
15168  triangle_refine.trianglearealist =
15169  (double*)malloc(triangulate_io.numberoftriangles * sizeof(double));
15170  for (unsigned count_area = 0; count_area < n_triangles; count_area++)
15171  {
15172  triangle_refine.trianglearealist[count_area] = target_area[count_area];
15173  }
15174 
15175  // Store the triangles attributes in the list
15176  triangle_refine.numberoftriangleattributes =
15177  triangulate_io.numberoftriangleattributes;
15178 
15179  triangle_refine.triangleattributelist = (double*)malloc(
15180  triangulate_io.numberoftriangles *
15181  triangulate_io.numberoftriangleattributes * sizeof(double));
15182  for (unsigned count_attribute = 0;
15183  count_attribute <
15184  (n_triangles * triangulate_io.numberoftriangleattributes);
15185  count_attribute++)
15186  {
15187  triangle_refine.triangleattributelist[count_attribute] =
15188  triangulate_io.triangleattributelist[count_attribute];
15189  }
15190  }
15191 
15192 #ifdef OOMPH_HAS_MPI
15193 
15194  // ===================================================================
15195  // The comparison class for the map that sorts the nodes on the
15196  // shared boundary (using a lexicographic order)
15197  // ===================================================================
15198  struct classcomp
15199  {
15200  // Tolerance for lower-left comparison
15201  static double Tol;
15202 
15203 
15204  // Comparison operator for "lower left" ordering
15205  bool operator()(const std::pair<double, double>& lhs,
15206  const std::pair<double, double>& rhs) const
15207  {
15208  double diff_y = lhs.second - rhs.second;
15209  if (diff_y < -Tol) // (lhs.second < rhs.second)
15210  {
15211  return true;
15212  }
15213  else
15214  {
15215  // Are they "equal" with 1.0e-14 tolerance?
15216  if (diff_y < Tol) // (lhs.second == rhs.second)
15217  {
15218 #ifdef PARANOID
15219  double diff_x = lhs.first - rhs.first;
15220  if (fabs(diff_x) < Tol)
15221  {
15222  std::ostringstream warning_message;
15223  warning_message
15224  << "Dodgy \"lower left\" (lexicographic) comparison "
15225  << "of points with cooordinates: "
15226  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15227  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15228  << "x and y coordinates differ by less than tolerance!\n"
15229  << "diff_x = " << diff_x << "\n"
15230  << "diff_y = " << diff_y << "\n"
15231  << "Tol = " << Tol << "\n";
15232  OomphLibError(warning_message.str(),
15233  OOMPH_CURRENT_FUNCTION,
15234  OOMPH_EXCEPTION_LOCATION);
15235  }
15236 #endif
15237  if (lhs.first < rhs.first)
15238  {
15239  return true;
15240  }
15241  else
15242  {
15243  return false;
15244  }
15245  }
15246  else
15247  {
15248  return false;
15249  }
15250  }
15251 
15252 
15253  // if (lhs.second < rhs.second)
15254  // {
15255  // return true;
15256  // }
15257  // else
15258  // {
15259  // // // Are "equal" with 1.0e-14 tolerance
15260  // // if (lhs.second - rhs.second < 1.0e-14)
15261  // // Are equal?
15262  // if (lhs.second == rhs.second)
15263  // {
15264  // if (lhs.first < rhs.first)
15265  // {
15266  // return true;
15267  // }
15268  // else
15269  // {
15270  // return false;
15271  // }
15272  // }
15273  // else
15274  // {
15275  // return false;
15276  // }
15277  // }
15278  }
15279 
15280  } Bottom_left_sorter; // struct classcomp
15281 
15282 
15283  // Assign value for tolerance
15284  double classcomp::Tol = 1.0e-14;
15285 
15286 
15287  //======================================================================
15288  // Sort the nodes on shared boundaries so that the processors that share
15289  // a boundary agree with the order of the nodes on the boundary
15290  //======================================================================
15291  template<class ELEMENT>
15293  {
15294  // Get the shared boundaries in this processor
15295  Vector<unsigned> my_rank_shared_boundaries_ids;
15296  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15297 
15298  // Get the number of shared boundaries
15299  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15300 
15301  // Loop over the shared boundaries
15302  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15303  {
15304  // A map is used to sort the nodes using their coordinates as the key
15305  // of the map
15306  // std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15307  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15308 
15309 
15310 #ifdef PARANOID
15311 
15312  // Check min distance between nodes; had better be less than the
15313  // tolerance used for the bottom left sorting
15314  double min_distance_squared = DBL_MAX;
15315 
15316 #endif
15317 
15318  // Get the boundary id
15319  const unsigned b = my_rank_shared_boundaries_ids[i];
15320 
15321  // Get the number of nodes on the current boundary
15322  const unsigned nbnd_node = this->nshared_boundary_node(b);
15323 
15324  // Go through all the nodes on the boundary and temporarily store
15325  // them on the map container
15326  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15327  {
15328  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15329  std::pair<double, double> vertex =
15330  std::make_pair(node_pt->x(0), node_pt->x(1));
15331  sorted_nodes_pt[vertex] = node_pt;
15332 
15333 
15334 #ifdef PARANOID
15335 
15336  // Check for minimum distance
15337  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15338  {
15339  if (i_node != j_node)
15340  {
15341  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15342 
15343  // Squared distance
15344  double squared_distance = 0.0;
15345  for (unsigned ii = 0; ii < 2; ii++)
15346  {
15347  squared_distance += (node_pt->x(ii) - node2_pt->x(ii)) *
15348  (node_pt->x(ii) - node2_pt->x(ii));
15349  }
15350  if (squared_distance < min_distance_squared)
15351  {
15352  min_distance_squared = squared_distance;
15353  }
15354  }
15355  }
15356 
15357  if (sqrt(min_distance_squared) < Bottom_left_sorter.Tol)
15358  {
15359  std::ostringstream warning_message;
15360  warning_message << "Minimum distance between nodes on boundary " << b
15361  << "\n"
15362  << "is " << sqrt(min_distance_squared)
15363  << " which is less than "
15364  << "Bottom_left_sorter.Tol = "
15365  << Bottom_left_sorter.Tol << "\n"
15366  << "This may screw up the ordering of the nodes on "
15367  "shared boundaries\n";
15368  OomphLibWarning(warning_message.str(),
15369  OOMPH_CURRENT_FUNCTION,
15370  OOMPH_EXCEPTION_LOCATION);
15371  }
15372 
15373 #endif
15374  }
15375 
15376  unsigned counter = 0;
15377  // Resize the sorted shared boundary node vector
15378  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15379 
15380  // Now go through the map container, get the elements and store their
15381  // members on the Sorted_shared_boundary_node_pt container
15382  // The map has already sorted the nodes, now they keep the same sorting
15383  // on all processors
15384  for (std::map<std::pair<double, double>, Node*>::iterator it_map =
15385  sorted_nodes_pt.begin();
15386  it_map != sorted_nodes_pt.end();
15387  it_map++)
15388  {
15389  // Store the pointer to the node
15390  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15391  }
15392 
15393  } // for (i < nmy_rank_shd_bnd)
15394  }
15395 
15396  //========================================================================
15397  // Re-establish the shared boundary elements after the adaptation
15398  // process (the updating of shared nodes is optional and performed by
15399  // default)
15400  //========================================================================
15401  template<class ELEMENT>
15404  const bool update_elements,
15405  const bool flush_nodes,
15406  const bool update_nodes)
15407  {
15408  // Get the rank of the current processor
15409  const unsigned my_rank = this->communicator_pt()->my_rank();
15410 
15411  // Go through the boundaries know as shared boundaries and copy the
15412  // elements to the corresponding storage
15413 
15414  // Get the initial shared boundary id
15415  const unsigned initial_id = this->initial_shared_boundary_id();
15416 
15417  // Get the final shared boundary id
15418  const unsigned final_id = this->final_shared_boundary_id();
15419 
15420  if (flush_elements)
15421  {
15422  // Flush the shared boundaries storage for elements
15423  this->flush_shared_boundary_element();
15424  // .. and also flush the face indexes associated with the element
15425  this->flush_face_index_at_shared_boundary();
15426  } // if (flush_elements)
15427 
15428  if (flush_nodes)
15429  {
15430  // Flush the shared boundaries storage for nodes
15431  this->flush_shared_boundary_node();
15432  } // if (flush_nodes)
15433 
15434  for (unsigned b = initial_id; b < final_id; b++)
15435  {
15436  // Check if the boundary is on the current processor
15437  Vector<unsigned> procs_from_shrd_bnd;
15438  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15439  bool current_processor_has_b_boundary = false;
15440  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15441  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15442  {
15443  if (procs_from_shrd_bnd[p] == my_rank)
15444  {
15445  current_processor_has_b_boundary = true;
15446  break; // break for (p < n_procs_from_shrd_bnd)
15447  }
15448  } // for (p < n_procs_from_shrd_bnd)
15449 
15450  if (current_processor_has_b_boundary)
15451  {
15452  if (update_elements)
15453  {
15454  const unsigned nboundary_ele = this->nboundary_element(b);
15455  for (unsigned e = 0; e < nboundary_ele; e++)
15456  {
15457  // Get the boundary element and add it to the shared
15458  // boundary elements structure
15459  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15460  this->add_shared_boundary_element(b, bnd_ele_pt);
15461  // ... do the same with the face index information
15462  int face_index = this->face_index_at_boundary(b, e);
15463  this->add_face_index_at_shared_boundary(b, face_index);
15464  } // for (e < nboundary_element)
15465  } // if (update_elements)
15466 
15467  if (update_nodes)
15468  {
15469  const unsigned nboundary_node = this->nboundary_node(b);
15470  for (unsigned n = 0; n < nboundary_node; n++)
15471  {
15472  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15473  this->add_shared_boundary_node(b, bnd_node_pt);
15474  } // for (n < nboundary_node)
15475  } // if (update_nodes)
15476 
15477  } // if (current_processor_has_b_boundary)
15478  } // for (b < final_id)
15479  }
15480 
15481  //======================================================================
15482  // Sort the nodes on shared boundaries so that the processors that share
15483  // a boundary agree with the order of the nodes on the boundary
15484  //======================================================================
15485  template<class ELEMENT>
15487  {
15488  // Get the number of processors
15489  unsigned nproc = this->communicator_pt()->nproc();
15490  // Get the rank of the current processor
15491  unsigned my_rank = this->communicator_pt()->my_rank();
15492 
15493  // Get some timings
15494  double tt_start = 0.0;
15495  double tt_end = 0.0;
15496  if (Global_timings::Doc_comprehensive_timings)
15497  {
15498  tt_start = TimingHelpers::timer();
15499  }
15500 
15501  // -------------------------------------------------------------------
15502  // BEGIN: Get the node names and the shared nodes
15503  // -------------------------------------------------------------------
15504 
15505  // Container where to store the nodes on shared boundaries no
15506  // associated with the processor that receives the elements/nodes
15507  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15508  Vector<Vector<Vector<std::map<unsigned, Node*>>>>
15509  other_proc_shd_bnd_node_pt(nproc);
15510  // Resize the container
15511  for (unsigned iproc = 0; iproc < nproc; iproc++)
15512  {
15513  // Resize the container
15514  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15515  for (unsigned jproc = 0; jproc < nproc; jproc++)
15516  {
15517  // Get the number of shared boundaries
15518  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15519  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15520  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15521  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15522  } // for (jproc < nproc)
15523 
15524  } // for (iproc < nproc)
15525 
15526  // Store the global node names
15527  // global_node_name[x][ ][ ] Global node number
15528  // global_node_name[ ][x][ ] Global node names
15529  // global_node_name[ ][ ][x] Global node info.
15530  Vector<Vector<Vector<unsigned>>> global_node_names;
15531 
15532  // Creates a map between the node name and the index of the global
15533  // node so we can access all its node names
15534  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15535 
15536  // Store the global shared nodes pointers
15537  Vector<Node*> global_shared_node_pt;
15538 
15539  // Get the time for computation of global nodes names and shared
15540  // nodes
15541  double t_start_global_node_names_and_shared_nodes = TimingHelpers::timer();
15542 
15543  // Compute all the names of the nodes and fill in the
15544  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15545  // on this processor (my_rank) by looking over all their names
15546  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15547  global_node_names,
15548  node_name_to_global_index,
15549  global_shared_node_pt);
15550 
15551  // Compute the number of elements before adding new ones
15552  const unsigned n_ele = this->nelement();
15553 
15554  if (Print_timings_level_adaptation > 1)
15555  {
15556  // The total time for computation of global nodes names and
15557  // shared nodes
15558  double t_final_global_node_names_and_shared_nodes =
15559  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15560  oomph_info << "CPU for computing global node names and shared nodes "
15561  << "[n_ele=" << n_ele
15562  << "]: " << t_final_global_node_names_and_shared_nodes
15563  << std::endl;
15564  }
15565 
15566  // -------------------------------------------------------------------
15567  // END: Get the node names and the shared nodes
15568  // -------------------------------------------------------------------
15569 
15570  // -------------------------------------------------------------------
15571  // BEGIN: Using the global node names each processor sends info. of
15572  // the nodes shared with other processors regarding whether they are
15573  // on an original boundary or not. This is required so that at the
15574  // re-generation of halo(ed) elements stage they have the updated
15575  // information
15576  // -------------------------------------------------------------------
15577 
15578  // Get the time for sending info. of shared nodes on original
15579  // boundaries
15580  double t_start_send_info_shd_nodes_on_original_bnds =
15581  TimingHelpers::timer();
15582 
15583  // Send the boundary node info. of nodes on shared boundaries across
15584  // processors
15585  send_boundary_node_info_of_shared_nodes(
15586  global_node_names, node_name_to_global_index, global_shared_node_pt);
15587 
15588  if (Print_timings_level_adaptation > 1)
15589  {
15590  // The total time for sending info. of shared nodes lying on
15591  // original boundaries
15592  oomph_info
15593  << "CPU for sending info. of shared nodes on original boundaries: "
15594  << TimingHelpers::timer() - t_start_send_info_shd_nodes_on_original_bnds
15595  << std::endl;
15596  }
15597 
15598  // -------------------------------------------------------------------
15599  // END: Using the global node names each processor sends info. of
15600  // the nodes shared with other processors regarding whether they are
15601  // on an original boundary or not. This is required so that at the
15602  // re-generation of halo(ed) elements stage they have the updated
15603  // information
15604  // -------------------------------------------------------------------
15605 
15606  // -------------------------------------------------------------------
15607  // BEGIN: Identify the elements of the mesh that have nodes on the
15608  // shared boundaries
15609  // -------------------------------------------------------------------
15610 
15611  // Store the elements that have a node on a shared boundary with
15612  // other processors
15613  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15614  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15615  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15616  // boundary with iproc
15617  Vector<Vector<Vector<FiniteElement*>>> ele_with_node_on_shd_bnd_pt(nproc);
15618  // Resize the container with the number of shared boundaries within
15619  // each processor
15620 
15621  // loop over the processors
15622  for (unsigned iproc = 0; iproc < nproc; iproc++)
15623  {
15624  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15625  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15626  } // for (iproc < nproc)
15627 
15628  // Go through all the elements and check whether any of their nodes
15629  // lies on any of the shared boundaries
15630 
15631  // loop over the elements
15632  for (unsigned e = 0; e < n_ele; e++)
15633  {
15634  // Get the element
15635  FiniteElement* ele_pt = this->finite_element_pt(e);
15636  // Get the number of nodes
15637  const unsigned n_nodes = ele_pt->nnode();
15638  // loop over the nodes and check whether any of them lies on a
15639  // shared boundary
15640  for (unsigned n = 0; n < n_nodes; n++)
15641  {
15642  // Get the node
15643  Node* node_pt = ele_pt->node_pt(n);
15644 
15645  // Now check whether the current node lies on a shared boundary
15646  // within any other processor
15647 
15648  // loop over the processors
15649  for (unsigned iproc = 0; iproc < nproc; iproc++)
15650  {
15651  // The number of boundaries shared with the current processor
15652  // (if iproc==my_rank then there are no shared boundaries
15653  // between them)
15654  const unsigned n_shd_bnd_iproc =
15655  this->nshared_boundaries(my_rank, iproc);
15656 
15657  // There are no info. with myself
15658  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15659  {
15660  // Get the boundaries ids of the shared boundaries with
15661  // iproc processor
15662  Vector<unsigned> shd_bnd_ids =
15663  this->shared_boundaries_ids(my_rank, iproc);
15664 
15665  // Loop over shd bnds with processor "iproc"
15666  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15667  {
15668  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15669  const unsigned n_ele_shd_bnd =
15670  this->nshared_boundary_element(shd_bnd_id);
15671 
15672  // Check if the node is on this boundary only if there are
15673  // elements on it
15674  if (n_ele_shd_bnd > 0 &&
15675  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15676  {
15677  // Add the element into those that have a
15678  // node on the current shared boundary
15679  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15680 
15681  } // Are there elements on the boundary and the node lies
15682  // on this boundary
15683 
15684  } // for (isb < n_shd_bnd_iproc)
15685 
15686  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15687 
15688  } // for (iproc < nproc)
15689 
15690  } // for (n < n_nodes)
15691 
15692  } // for (e < n_ele)
15693 
15694  // -------------------------------------------------------------------
15695  // END: Identify the elements of the mesh that have nodes on the
15696  // shared boundaries
15697  // -------------------------------------------------------------------
15698 
15699  // -------------------------------------------------------------------
15700  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15701  // the shared boundaries within each processor. Get the elements on
15702  // the shared boundaries, mark them as haloed in this processor and
15703  // as halo on the element that will receive the info.
15704  // -------------------------------------------------------------------
15705 
15706  // ********************************************************************
15707  // General strategy:
15708  // 1) Go through all the elements on the shared boundaries, mark these
15709  // elements as haloed, same as their nodes.
15710  // 2) Package the info. of the nodes and the elements.
15711  // 3) Send and receive the info across processors
15712  // 4) Unpackage it and create halo elements and nodes as indicated by
15713  // the received info.
15714  // ********************************************************************
15715 
15716  // Keep track of the currently created nodes within each
15717  // processor. We need to keep track of these nodes so they can be
15718  // referred at a second stage.
15719  Vector<Vector<Node*>> iproc_currently_created_nodes_pt(nproc);
15720 
15721  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15722  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15723  TimingHelpers::timer();
15724 
15725  // Go through all processors
15726  for (unsigned iproc = 0; iproc < nproc; iproc++)
15727  {
15728  // Send and receive info. to/from other processors
15729  if (iproc != my_rank)
15730  {
15731  // Get the number of boundaries shared with the send proc (iproc)
15732  const unsigned nshared_boundaries_with_iproc =
15733  this->nshared_boundaries(my_rank, iproc);
15734 
15735  if (nshared_boundaries_with_iproc > 0)
15736  {
15737  // ******************************************************************
15738  // Stage 1
15739  // ******************************************************************
15740  // Step (1) Mark the elements adjacent to the shared boundaries as
15741  // haloed, mark the nodes on these elements as haloed nodes
15742  // Step (2) Create packages of information indicating the generation
15743  // of halo elements and nodes
15744  // ******************************************************************
15745 
15746  // Clean send and receive buffers
15747  Flat_packed_unsigneds.clear();
15748  Flat_packed_doubles.clear();
15749 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15750  Flat_packed_unsigneds_string.clear();
15751 #endif
15752 
15753  // Get the boundaries ids shared with "iproc"
15754  Vector<unsigned> bound_shared_with_iproc;
15755  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15756 
15757  // Loop over shared boundaries with processor "iproc"
15758  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15759  {
15760  const unsigned bnd_id = bound_shared_with_iproc[bs];
15761  // DEBP(bnd_id);
15762  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15763  // DEBP(nel_bnd);
15764 
15765  // Container to store the elements marked as haloed
15766  Vector<FiniteElement*> haloed_element;
15767 
15768  // All the elements adjacent to the boundary should be
15769  // marked as haloed elements
15770  if (nel_bnd > 0)
15771  {
15772  // Map to know which element have been already added
15773  std::map<FiniteElement*, bool> already_added;
15774 
15775  // Loop over the elements adjacent to boundary "bnd_id"
15776  for (unsigned e = 0; e < nel_bnd; e++)
15777  {
15778  // Get pointer to the element adjacent to boundary bnd_id
15779  FiniteElement* ele_pt =
15780  this->shared_boundary_element_pt(bnd_id, e);
15781 
15782  // Check if the element has been already added. Elemets
15783  // are repeated if they have two faces on the shared
15784  // boundary
15785  if (!already_added[ele_pt])
15786  {
15787  // Add the element to the container of haloed elements
15788  haloed_element.push_back(ele_pt);
15789  // Mark the element as already added
15790  already_added[ele_pt] = true;
15791  }
15792 
15793  } // for (e < nel_bnd)
15794 
15795  // In addition to the elements on the boundary we also
15796  // need to mark (as haloed) any element on the mesh with a
15797  // node on the shared boundary
15798 
15799  // Get the number of elements with a node on the current
15800  // shared boundary
15801  const unsigned n_ele_with_node_on_shd_bnd =
15802  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15803  // loop and add the elements that have a node on the
15804  // current shared boundary with the current processor
15805  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15806  {
15807  // Get the element
15808  FiniteElement* ele_pt =
15809  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15810  // Check if it has not been already added
15811  if (!already_added[ele_pt])
15812  {
15813  // Add it!!
15814  haloed_element.push_back(ele_pt);
15815  // Mark it as done
15816  already_added[ele_pt] = true;
15817  } // if (!already_added[ele_pt])
15818 
15819  } // for (iele < n_ele_with_node_on_shd_bnd)
15820 
15821  } // if (nel_bnd > 0)
15822 
15823  // Get the total number of haloed elements
15824  const unsigned nhaloed_ele = haloed_element.size();
15825  // DEBP(nhaloed_ele);
15826  // DEBP(my_rank);
15827  // DEBP(iproc);
15828  // The very first data of the flat packed is the number of haloed
15829  // elements, this will be the number of halo element to create on
15830  // the receiver processor
15831  Flat_packed_unsigneds.push_back(nhaloed_ele);
15832 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15833  std::stringstream junk;
15834  junk << "Number of haloed elements " << nhaloed_ele;
15835  Flat_packed_unsigneds_string.push_back(junk.str());
15836 #endif
15837 
15838  // Loop over the marked haloed elements
15839  for (unsigned e = 0; e < nhaloed_ele; e++)
15840  {
15841  // Get pointer to the marked haloed element
15842  FiniteElement* ele_pt = haloed_element[e];
15843  const unsigned nroot_haloed_ele =
15844  this->nroot_haloed_element(iproc);
15845 
15846  // Check if the element has been already added to the
15847  // halo(ed) scheme
15848  GeneralisedElement* gen_ele_pt = ele_pt;
15849  const unsigned haloed_ele_index =
15850  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15851 
15852  // Was the element added or only returned the index of the
15853  // element
15854  if (nroot_haloed_ele == haloed_ele_index)
15855  {
15856  Flat_packed_unsigneds.push_back(1);
15857 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15858  Flat_packed_unsigneds_string.push_back(
15859  "Haloed element needs to be constructed");
15860 #endif
15861 
15862  // Get additional info. related with the haloed element
15863  get_required_elemental_information_helper(iproc, ele_pt);
15864 
15865  // Get the nodes on the element
15866  const unsigned nnodes = ele_pt->nnode();
15867  for (unsigned j = 0; j < nnodes; j++)
15868  {
15869  Node* node_pt = ele_pt->node_pt(j);
15870 
15871  // Package the info. of the nodes
15872  // The destination processor goes in the arguments
15873  add_haloed_node_helper(iproc, node_pt);
15874 
15875  } // for (j < nnodes)
15876  } // add the element and send its nodes
15877  else // The haloed element already exists
15878  {
15879  Flat_packed_unsigneds.push_back(0);
15880 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15881  Flat_packed_unsigneds_string.push_back(
15882  "Haloed element already exists");
15883 #endif
15884  Flat_packed_unsigneds.push_back(haloed_ele_index);
15885 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15886  Flat_packed_unsigneds_string.push_back(
15887  "Index of existing haloed element");
15888 #endif
15889  } // else (next_haloed_ele == external_haloed_ele_index)
15890  } // for (e < nel_bnd)
15891 
15892  } // for (bs < nshared_boundaries_with_iproc)
15893 
15894  // *******************************************************************
15895  // Stage (2)
15896  // *******************************************************************
15897  // Step (1) Send and receive the data to create halo elements and
15898  // nodes
15899  // *******************************************************************
15900  // The processor to which send the elements
15901  int send_proc = static_cast<int>(iproc);
15902  // The processor from which receive the elements
15903  int recv_proc = static_cast<int>(iproc);
15904  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15905 
15906  // *******************************************************************
15907  // Stage (3)
15908  // *******************************************************************
15909  // Step (1) Unpackage the info and create the halo elements and nodes
15910  // *******************************************************************
15911 
15912  // Reset the counters
15913  Counter_for_flat_packed_doubles = 0;
15914  Counter_for_flat_packed_unsigneds = 0;
15915 
15916  // Loop over shared boundaries with processor "iproc"
15917  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15918  {
15919  // Get the number of halo element to be created
15920  const unsigned nhaloed_ele =
15921  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
15922 
15923 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15924  oomph_info
15925  << "Rec:" << Counter_for_flat_packed_unsigneds
15926  << " Number of elements need to be constructed "
15927  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
15928  << std::endl;
15929 #endif
15930 
15931  // Loop over boundaries shared with processor "urecv_proc"
15932  for (unsigned e = 0; e < nhaloed_ele; e++)
15933  {
15934  // Create halo element from received info. of "iproc"
15935  // processor on the current processor
15936  create_halo_element(iproc,
15937  iproc_currently_created_nodes_pt[iproc],
15938  other_proc_shd_bnd_node_pt,
15939  global_node_names,
15940  node_name_to_global_index,
15941  global_shared_node_pt);
15942 
15943  } // for (e < nhaloed_ele)
15944 
15945  } // for (bs < nshared_boundaries_with_iproc)
15946 
15947  } // if (nshared_bound_recv_proc > 0)
15948 
15949  } // if (iproc != my_rank)
15950 
15951  } // for (iproc < nproc) (general loop to send and receive info.)
15952 
15953  if (Print_timings_level_adaptation > 1)
15954  {
15955  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15956  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15957  TimingHelpers::timer() -
15958  t_start_regenerate_halo_ed_elements_nodes_first_stage;
15959 
15960  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15961  << "(first stage) [n_ele=" << n_ele << "]: "
15962  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15963  << std::endl;
15964  }
15965 
15966  // -------------------------------------------------------------------
15967  // END: Create the halo(ed) elements. Loop over the processors and
15968  // the shared boundaries within each processor. Get the elements on
15969  // the shared boundaries, mark them as haloed in this processor and
15970  // as halo on the element that will receive the info.
15971  // -------------------------------------------------------------------
15972 
15973  // -------------------------------------------------------------------
15974  // BEGIN: Create any additional haloed element, those that dont lie
15975  // on a shared boundary but that shared a node with other processor
15976  // -------------------------------------------------------------------
15977 
15978  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15979  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15980  TimingHelpers::timer();
15981 
15982  // Create any additional halo(ed) elements between processors that
15983  // have no shared boundaries but that have shared nodes
15984  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15985  iproc_currently_created_nodes_pt,
15986  global_node_names,
15987  node_name_to_global_index,
15988  global_shared_node_pt);
15989 
15990  if (Print_timings_level_adaptation > 1)
15991  {
15992  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15993  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
15994  TimingHelpers::timer() -
15995  t_start_regenerate_halo_ed_elements_nodes_second_stage;
15996 
15997  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15998  << "(second stage) [n_ele=" << n_ele << "]: "
15999  << t_final_regenerate_halo_ed_elements_nodes_second_stage
16000  << std::endl;
16001  }
16002 
16003  // -------------------------------------------------------------------
16004  // END: Create any additional haloed element, those that dont lie on
16005  // a shared boundary but that shared a node with other processor
16006  // -------------------------------------------------------------------
16007 
16008  // Clean send and receive buffers
16009  Flat_packed_unsigneds.clear();
16010  Flat_packed_doubles.clear();
16011 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
16012  Flat_packed_unsigneds_string.clear();
16013 #endif
16014 
16015  // Document the timings for reseting halo and haloed scheme (without
16016  // classification of halo and haloed nodes)
16017  if (Print_timings_level_adaptation > 1)
16018  {
16019  tt_end = TimingHelpers::timer();
16020  oomph_info << "CPU for resetting halo-haloed scheme (without "
16021  "classification of halo and haloed nodes): "
16022  << tt_end - tt_start << std::endl;
16023  }
16024 
16025  // ------------------------------------------------------------------
16026  // BEGIN: Classify halo(ed) elements and nodes
16027  // ------------------------------------------------------------------
16028  const bool report_stats = true;
16029  DocInfo tmp_doc_info;
16030  tmp_doc_info.disable_doc();
16031 
16032  // Classify nodes
16033  this->classify_halo_and_haloed_nodes(tmp_doc_info, report_stats);
16034 
16035  // Document the timings for reseting halo and haloed scheme (with
16036  // classification of halo and haloed nodes)
16037  if (Print_timings_level_adaptation > 1)
16038  {
16039  tt_end = TimingHelpers::timer();
16040  oomph_info << "CPU for resetting halo-haloed scheme (with classification "
16041  "of halo and haloed nodes): "
16042  << tt_end - tt_start << std::endl;
16043  }
16044 
16045  // ------------------------------------------------------------------
16046  // END: Classify halo(ed) elements and nodes
16047  // ------------------------------------------------------------------
16048  }
16049 
16050  //======================================================================
16051  // \short Compute the alias of the nodes on shared boundaries in this
16052  // (my_rank) processor with other processors. Also compute the alias
16053  // of nodes on shared boundaries of other processors with other
16054  // processors (useful when there is an element that requires to be
16055  // sent to this (my_rank) processor because there is a shared node
16056  // between this (my_rank) and other processors BUT there is not a
16057  // shared boundary between this and the other processor
16058  // ======================================================================
16059  template<class ELEMENT>
16062  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
16063  other_proc_shd_bnd_node_pt,
16064  Vector<Vector<Vector<unsigned>>>& global_node_names,
16065  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
16066  Vector<Node*>& global_shared_node_pt)
16067  {
16068  // Get the number of processors
16069  const unsigned nproc = this->communicator_pt()->nproc();
16070  // Get the rank of the current processor
16071  const unsigned my_rank = this->communicator_pt()->my_rank();
16072  // Get the communicator of the mesh
16073  OomphCommunicator* comm_pt = this->communicator_pt();
16074 
16075  // ---------------------------------------------------------------
16076  // BEGIN: Get the elements adjacent to shared boundaries and give
16077  // a unique node number to the nodes on the shared boundaries in
16078  // this processor
16079  // ---------------------------------------------------------------
16080 
16081  // Counter for the nodes on shared boundaries in this (my_rank)
16082  // processor
16083  unsigned counter_nodes = 0;
16084  // Keep track of visited nodes
16085  std::map<Node*, bool> done_node;
16086  // ... and its local node number
16087  std::map<Node*, unsigned> local_node_number;
16088  // ... and the inverted relation from local node number to node_pt
16089  Vector<Node*> local_node_pt;
16090 
16091  // Stores the j-th node name associated with the i-th local node
16092  // on shared boundaries in this processor (my_rank)
16093  // local_node_names[i][j][0] = my_rank (this processor)
16094  // local_node_names[i][j][1] = iproc (the processor with which there
16095  // is a shared boundary)
16096  // local_node_names[i][j][2] = the shared boundary id between this
16097  // (my_rank) processor and iproc
16098  // processor
16099  // local_node_names[i][j][3] = the node index on the shared boundary
16100  // local_node_names[i][j][4] = the local node index (i). This may
16101  // be unnecessary since we alread know the
16102  // index but we also send this info. to
16103  // the root processor that is why we store
16104  // them here
16105  Vector<Vector<Vector<unsigned>>> local_node_names;
16106 
16107  // loop over the processors
16108  for (unsigned iproc = 0; iproc < nproc; iproc++)
16109  {
16110  // There are not shared boundaries with myself
16111  if (iproc != my_rank)
16112  {
16113  // Get the number of shared boundaries with iproc
16114  const unsigned n_shd_bnds_with_iproc =
16115  this->nshared_boundaries(my_rank, iproc);
16116 
16117  // Get the boundaries ids shared with iproc
16118  Vector<unsigned> bnd_shd_with_iproc =
16119  this->shared_boundaries_ids(my_rank, iproc);
16120 
16121  // Loop over the shared boundaries with processor iproc
16122  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
16123  {
16124  // Keep track of visited nodes with this shared boundary
16125  std::map<Node*, bool> done_node_shd_bnd;
16126  // The boundary id
16127  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
16128  // Get the number of element on the shared boundary
16129  const unsigned n_shd_bnd_ele =
16130  this->nshared_boundary_element(shd_bnd_id);
16131 
16132  // loop over the elements adjacent to the shared boundary
16133  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
16134  {
16135  // Get the element
16136  FiniteElement* ele_pt =
16137  this->shared_boundary_element_pt(shd_bnd_id, e);
16138 
16139  // Get the number of nodes on the element
16140  const unsigned n_nodes = ele_pt->nnode();
16141 
16142  // loop over the nodes of the current element
16143  for (unsigned n = 0; n < n_nodes; n++)
16144  {
16145  // Get the node
16146  Node* node_pt = ele_pt->node_pt(n);
16147 
16148  // Has the node been visited with this shared boundary?
16149  // And, is this a node on the shd_bnd_id shared boundary
16150  // with processor iproc?
16151  if (!done_node_shd_bnd[node_pt] &&
16152  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
16153  {
16154  // Mark the done as done with this shared boundary
16155  done_node_shd_bnd[node_pt] = true;
16156 
16157  // Get the index of the node on the shared boundary
16158  // -------------------------------------------------
16159  // Get the number of nodes on the shared boundary
16160  const unsigned n_nodes_shd_bnd =
16161  nsorted_shared_boundary_node(shd_bnd_id);
16162 
16163  // The index
16164  unsigned index = 0;
16165 
16166 #ifdef PARANOID
16167  // Flag to know if the node has been found
16168  bool found_node_on_shared_boundary = false;
16169 #endif
16170  // Loop over the nodes on the shared boundary to find
16171  // the node
16172  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16173  {
16174  // Get the k-th node on the shared boundary
16175  Node* shd_bnd_node_pt =
16176  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16177 
16178  // Is the same node?
16179  if (shd_bnd_node_pt == node_pt)
16180  {
16181  // This is the index
16182  index = k;
16183 #ifdef PARANOID
16184  // Mark as found
16185  found_node_on_shared_boundary = true;
16186 #endif
16187  break; // break
16188 
16189  } // if (shd_bnd_node_pt == node_pt)
16190 
16191  } // for (k < n_nodes_shd_bnd)
16192 
16193 #ifdef PARANOID
16194  if (!found_node_on_shared_boundary)
16195  {
16196  std::ostringstream error_message;
16197  error_message << "The index of the node on boundary ("
16198  << shd_bnd_id << ") was not found.\n"
16199  << "These are the node coordinates\n"
16200  << "(" << node_pt->x(0) << "," << node_pt->x(1)
16201  << ").\n";
16202  throw OomphLibError(error_message.str(),
16203  OOMPH_CURRENT_FUNCTION,
16204  OOMPH_EXCEPTION_LOCATION);
16205  }
16206 #endif
16207 
16208  // Create the node name
16209  Vector<unsigned> node_name(5);
16210  node_name[0] = my_rank;
16211  node_name[1] = iproc;
16212  node_name[2] = shd_bnd_id;
16213  node_name[3] = index;
16214  // The node number is filled in the following if/else
16215  // node_name[4] = ?;
16216 
16217  // Has the node already been visited?
16218  if (!done_node[node_pt])
16219  {
16220  // If not ...
16221 
16222  // Add the node to the local nodes
16223  local_node_pt.push_back(node_pt);
16224 
16225  // Assign a local node number to the node
16226  local_node_number[node_pt] = counter_nodes;
16227  // Store the local node number
16228  node_name[4] = counter_nodes;
16229  // Increase the counter of nodes
16230  counter_nodes++;
16231  // ... and mark it as visited
16232  done_node[node_pt] = true;
16233 
16234  // Push back the node name (the first
16235  // one found for this node)
16236  Vector<Vector<unsigned>> first_node_name(1);
16237  first_node_name[0] = node_name;
16238  local_node_names.push_back(first_node_name);
16239  }
16240  else
16241  {
16242  // If yes ...
16243 
16244  // Get the local node number
16245  unsigned node_number = local_node_number[node_pt];
16246 
16247  // Store the local node number
16248  node_name[4] = node_number;
16249 
16250  // Push back the node name for the
16251  // node number
16252  local_node_names[node_number].push_back(node_name);
16253  }
16254 
16255  } // Is on shared boundary?
16256 
16257  } // for (n < nnodes)
16258 
16259  } // for (e < n_shd_bnd_ele)
16260 
16261  } // for (ishd < n_shd_bnds_with_iproc)
16262 
16263  } // if (iproc != my_rank)
16264 
16265  } // for (iproc < nproc)
16266 
16267  // ---------------------------------------------------------------
16268  // END: Get the elements adjacent to shared boundaries and give
16269  // a unique node number to the nodes on the shared boundaries in
16270  // this processor
16271  // ---------------------------------------------------------------
16272 
16273  // ---------------------------------------------------------------
16274  // BEGIN: Package the names of the local nodes
16275  // ---------------------------------------------------------------
16276  // Counter for the number of names of the nodes
16277  unsigned n_total_local_names = 0;
16278  // Get the number of local nodes
16279  const unsigned n_local_nodes = local_node_names.size();
16280  // loop over the number of local nodes and get the number of names
16281  // of each node
16282  for (unsigned i = 0; i < n_local_nodes; i++)
16283  {
16284  // Get the number of names of the i-th local node
16285  const unsigned n_inode_names = local_node_names[i].size();
16286  // ... and add them to the total number of local names
16287  n_total_local_names += n_inode_names;
16288  } // for (i < n_local_nodes)
16289 
16290  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16291  // where node# is the node number on this processor (my_rank)
16292  const unsigned n_info_per_node_name = 5;
16293  // Storage for the flat package
16294  Vector<unsigned> flat_packed_send_udata(n_total_local_names *
16295  n_info_per_node_name);
16296  // A counter
16297  unsigned counter = 0;
16298  // loop over the local nodes
16299  for (unsigned i = 0; i < n_local_nodes; i++)
16300  {
16301  // Get the number of names of the i-th local node
16302  const unsigned n_inode_names = local_node_names[i].size();
16303  // loop over the names of the i-th local node
16304  for (unsigned j = 0; j < n_inode_names; j++)
16305  {
16306  // Store this processor id (my_rank)
16307  flat_packed_send_udata[counter++] = local_node_names[i][j][0];
16308  // Store the processor with which the shared boundary exist
16309  flat_packed_send_udata[counter++] = local_node_names[i][j][1];
16310  // Store the shared boundary id
16311  flat_packed_send_udata[counter++] = local_node_names[i][j][2];
16312  // Store the index of the node on the shared boundary
16313  flat_packed_send_udata[counter++] = local_node_names[i][j][3];
16314  // Store the local node number on this processor (my_rank)
16315  flat_packed_send_udata[counter++] = local_node_names[i][j][4];
16316  } // for (j < n_inode_names)
16317 
16318  } // for (i < n_local_nodes)
16319 
16320  // Reset the counter
16321  counter = 0;
16322 
16323  // The number of data that will be sent to root from this
16324  // (my_rank) processor
16325  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16326 
16327  // ---------------------------------------------------------------
16328  // END: Package the names of the local nodes
16329  // ---------------------------------------------------------------
16330  // ---------------------------------------------------------------
16331  // BEGIN: Send the data to the root processor
16332  // ---------------------------------------------------------------
16333 
16334  // The root processor is in charge of computing all the node names
16335  // of the nodes on the shared boundaries
16336 
16337  // Choose the root processor
16338  const unsigned root_processor = 0;
16339 
16340  // The vector where the root processor receives how many names
16341  // will receive from the other processors
16342  Vector<unsigned> root_n_names_per_processor(nproc);
16343 
16344  // Send the number of names that the root processor will receive
16345  // from each processor
16346  MPI_Gather(&n_total_local_names,
16347  1,
16348  MPI_UNSIGNED,
16349  &root_n_names_per_processor[0],
16350  1,
16351  MPI_UNSIGNED,
16352  root_processor,
16353  comm_pt->mpi_comm());
16354 
16355  // Get the total number of data to receive from all processor in
16356  // root
16357  unsigned root_n_total_udata_receive = 0;
16358  Vector<int> root_n_udata_to_receive(nproc, 0);
16359  for (unsigned iproc = 0; iproc < nproc; iproc++)
16360  {
16361  root_n_udata_to_receive[iproc] =
16362  root_n_names_per_processor[iproc] * n_info_per_node_name;
16363  root_n_total_udata_receive += root_n_udata_to_receive[iproc];
16364  }
16365 
16366  // Stores and compute the offsets (in root) for the data received
16367  // from each processor
16368  Vector<int> root_uoffsets_receive(nproc, 0);
16369  root_uoffsets_receive[0] = 0;
16370  for (unsigned iproc = 1; iproc < nproc; iproc++)
16371  {
16372  // Compute the offset to obtain the data from each processor
16373  root_uoffsets_receive[iproc] =
16374  root_uoffsets_receive[iproc - 1] + root_n_udata_to_receive[iproc - 1];
16375  }
16376 
16377  // Create at least one entry so we don't get a seg fault below
16378  if (flat_packed_send_udata.size() == 0)
16379  {
16380  flat_packed_send_udata.resize(1);
16381  }
16382 
16383  // Vector where to receive the info on root from all processors
16384  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16385  // Only root receive data, the others dont, then resize the
16386  // container to have at least one entry
16387  if (my_rank != root_processor)
16388  {
16389  // Create at least one entry so we don't get a seg fault below
16390  if (root_flat_packed_receive_udata.size() == 0)
16391  {
16392  root_flat_packed_receive_udata.resize(1);
16393  }
16394  } // if (my_rank!=root_processor)
16395 
16396  // Send the info. to the root processor
16397  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16398  // info. from each
16399  // processor
16400  n_udata_send_to_root, // Total number of data send
16401  // from each processor to root
16402  MPI_UNSIGNED,
16403  &root_flat_packed_receive_udata[0], // Container where
16404  // to receive the
16405  // info. from all
16406  // processors
16407  &root_n_udata_to_receive[0], // Number of data to
16408  // receive from each
16409  // processor
16410  &root_uoffsets_receive[0], // The offset to store the
16411  // info. from each
16412  // processor
16413  MPI_UNSIGNED,
16414  root_processor, // The processor that receives all the
16415  // info.
16416  comm_pt->mpi_comm());
16417 
16418  // Clear and resize the flat package to send
16419  flat_packed_send_udata.clear();
16420  flat_packed_send_udata.resize(0);
16421  // ---------------------------------------------------------------
16422  // END: Send the data to the root processor
16423  // ---------------------------------------------------------------
16424 
16425  // Container where root stores the info. that will be sent to all
16426  // processors. This includes the number of global nodes, the
16427  // number of names for each global node and the names
16428  Vector<unsigned> flat_packed_root_send_receive_udata;
16429 
16430  // ---------------------------------------------------------------
16431  // BEGIN: Unpackage the info. received on root. Compute the alias
16432  // of the nodes
16433  // ---------------------------------------------------------------
16434  if (my_rank == root_processor)
16435  {
16436  // Compute all the names of a node
16437  // root_global_node_name[x][ ][ ] Global node number
16438  // root_global_node_name[ ][x][ ] Global node names
16439  // root_global_node_name[ ][ ][x] Global node info.
16440  Vector<Vector<Vector<unsigned>>> root_global_node_names;
16441 
16442  // Store the info. extracted from the flat package sent to
16443  // root
16444  // root_local_node_names[x][ ] Node name
16445  // root_local_node_names[ ][x] Node info
16446  Vector<Vector<unsigned>> root_local_node_names;
16447 
16448  // Extract all the node names
16449  unsigned rcounter = 0;
16450  // loop over the processors
16451  for (unsigned iproc = 0; iproc < nproc; iproc++)
16452  {
16453  // Get the number of node names received from iproc
16454  const unsigned n_local_names_iproc = root_n_names_per_processor[iproc];
16455  for (unsigned i = 0; i < n_local_names_iproc; i++)
16456  {
16457  // Get the i-thnode name from iproc
16458  Vector<unsigned> node_name(n_info_per_node_name);
16459  for (unsigned j = 0; j < n_info_per_node_name; j++)
16460  {
16461  node_name[j] = root_flat_packed_receive_udata[rcounter++];
16462  }
16463 
16464  // Add the i-th node name
16465  root_local_node_names.push_back(node_name);
16466 
16467  } // for (i < n_local_names_iproc)
16468 
16469  } // for (iproc < nproc)
16470 
16471  // Get the number of node names received
16472  const unsigned n_root_local_node_names = root_local_node_names.size();
16473 
16474  // For each name of the node identify the position of its
16475  // counter-part
16476 
16477  // Given a node name on the iproc,
16478  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16479  // its counter part must live in jproc, so we look for the
16480  // node name
16481  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16482 
16483  // Store the index of the node name counter-part
16484  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16485 
16486  // Keep track of the names of nodes already done
16487  std::map<Vector<unsigned>, bool> done_name;
16488 
16489  // loop over the names of the nodes received from all
16490  // processors
16491  for (unsigned i = 0; i < n_root_local_node_names; i++)
16492  {
16493  // Get the i-th node name
16494  Vector<unsigned> node_name = root_local_node_names[i];
16495 
16496  // Check if this name node has been already done
16497  if (!done_name[node_name])
16498  {
16499  // Mark it as done
16500  done_name[node_name] = true;
16501 #ifdef PARANOID
16502  // Flag to indicate the counter-part name node was
16503  // found
16504  bool found_both_names_node = false;
16505 #endif
16506  // Find the counter-part name node (start from j+1
16507  // since all previous have been found, otherwise we
16508  // would not be here)
16509  for (unsigned j = i + 1; j < n_root_local_node_names; j++)
16510  {
16511  Vector<unsigned> node_name_r = root_local_node_names[j];
16512 
16513  // Check if this name node has been already done
16514  if (!done_name[node_name_r])
16515  {
16516  // Check whether this node is the
16517  // counter-part of the current name node
16518  if (node_name[0] == node_name_r[1] &&
16519  node_name[1] == node_name_r[0] &&
16520  node_name[2] == node_name_r[2] &&
16521  node_name[3] == node_name_r[3])
16522  {
16523  // Mark the name as node
16524  done_name[node_name_r] = true;
16525  // Store the index of the counter-part of
16526  // the current node name
16527  node_name_counter_part[i] = j;
16528  // ... and indicate the current node name
16529  // as the index of the counter-part
16530  node_name_counter_part[j] = i;
16531 #ifdef PARANOID
16532  // The node has been found
16533  found_both_names_node = true;
16534 #endif
16535  // Break the loop to find the
16536  // counter-part
16537  break;
16538  }
16539 
16540  } // if (!done_name[node_name_r])
16541 
16542  } // for (j < n_root_local_node_names)
16543 #ifdef PARANOID
16544  // Check whether the node counter-part was found
16545  if (!found_both_names_node)
16546  {
16547  std::ostringstream error_message;
16548  error_message << "The counter-part of the current name node was "
16549  << "not found,\nthe current node name is:\n"
16550  << "iproc:(" << node_name[0] << ")\n"
16551  << "jproc:(" << node_name[1] << ")\n"
16552  << "ishd_bnd:(" << node_name[2] << ")\n"
16553  << "index:(" << node_name[3] << ")\n";
16554  throw OomphLibError(error_message.str(),
16555  OOMPH_CURRENT_FUNCTION,
16556  OOMPH_EXCEPTION_LOCATION);
16557  } // if (!found_both_names_node)
16558 #endif
16559 
16560  } // if (!done_name[node_name])
16561 
16562  } // for (i < n_root_local_node_names)
16563 
16564  // -----------------------------------------------------------
16565  // Look for all the names of each node received and store them
16566  // in the "global node names" container
16567 
16568  // Keep track of the names of nodes already done
16569  done_name.clear();
16570  // loop over the names of the nodes received from all
16571  // processors
16572  for (unsigned i = 0; i < n_root_local_node_names; i++)
16573  {
16574  // Get the i-th node name
16575  Vector<unsigned> node_name = root_local_node_names[i];
16576 
16577  // Check if this name node has been already done
16578  if (!done_name[node_name])
16579  {
16580  // Store all the names of the current node
16581  Vector<Vector<unsigned>> all_node_names;
16582 
16583  // Add the name of the node as the initial node name
16584  all_node_names.push_back(node_name);
16585 
16586  // Get the index of the counter-part
16587  unsigned idx_c = node_name_counter_part[i];
16588  // Get the counter-part of the node name
16589  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16590 
16591  // Add the name of the counter-part of the node
16592  all_node_names.push_back(node_name_r);
16593  // We do not mark it as done since we are interested in
16594  // the names that the counter-part may generate
16595 
16596  // Get the number of names for the current node (two at
16597  // the first time)
16598  unsigned n_current_names = all_node_names.size();
16599  // Counter to ensure to visit all the names of the current
16600  // node
16601  unsigned icounter = 0;
16602 
16603  // Visit all the names of the current node
16604  while (icounter < n_current_names)
16605  {
16606  // Get the current node name
16607  Vector<unsigned> current_node_name = all_node_names[icounter];
16608 
16609  // Search for other names for the current name of the
16610  // node, but first check if this has been already
16611  // visited
16612  if (!done_name[current_node_name])
16613  {
16614  // Mark it as done
16615  done_name[current_node_name] = true;
16616 
16617  // loop over the names of the nodes (start from the
16618  // j+1 position, all previous node names have all
16619  // their names already assigned)
16620  for (unsigned j = i + 1; j < n_root_local_node_names; j++)
16621  {
16622  // Get the j-th node name
16623  Vector<unsigned> other_node_name = root_local_node_names[j];
16624 
16625  // Is this name node already done
16626  if (!done_name[other_node_name])
16627  {
16628  // Is this another name for the current name node?
16629  if ((current_node_name[0] == other_node_name[0]) &&
16630  (current_node_name[4] == other_node_name[4]))
16631  {
16632  // Mark it as done. If we search again using the
16633  // "other_node_name" as the current node name we
16634  // are not going to find new nodes to add
16635  done_name[other_node_name] = true;
16636  // Before adding it check that it is not already
16637  // part of the names of the node
16638  Vector<Vector<unsigned>>::iterator it =
16639  std::find(all_node_names.begin(),
16640  all_node_names.end(),
16641  other_node_name);
16642  if (it == all_node_names.end())
16643  {
16644  all_node_names.push_back(other_node_name);
16645  // Get the index of the counter-part
16646  unsigned k = node_name_counter_part[j];
16647  // Get the counter-part of the node name
16648  Vector<unsigned> other_node_name_r =
16649  root_local_node_names[k];
16650  // Add the name of the counter-part of the
16651  // node only if it has not been previously
16652  // done
16653  if (!done_name[other_node_name_r])
16654  {
16655  all_node_names.push_back(other_node_name_r);
16656  }
16657  }
16658 
16659  } // // Is this another name for the current name
16660  // node?
16661 
16662  } // if (!done_name[other_node_name])
16663 
16664  } // for (j < n_root_local_node_names)
16665 
16666  } // if (!done_name[current_node_name])
16667 
16668  // Get the number of names
16669  n_current_names = all_node_names.size();
16670  // Increase the icounter to indicate we have visited the
16671  // current name of the node
16672  icounter++;
16673 
16674  } // while(icounter < n_current_names)
16675 
16676  // We now have all the names for the i-th global node
16677  root_global_node_names.push_back(all_node_names);
16678 
16679  } // if (!done_name[node_name])
16680 
16681  } // for (i < n_root_local_node_names)
16682 
16683  // -------------------------------------------------------------
16684  // Prepare the info to be sent to all processors. The number
16685  // of global nodes, the number of names for each global node,
16686  // and their respective names
16687  // -------------------------------------------------------------
16688 
16689  // Clear the container
16690  flat_packed_root_send_receive_udata.clear();
16691  // Get the number of global nodes
16692  const unsigned n_global_nodes = root_global_node_names.size();
16693  // ... and store this info. to be sent from root to all
16694  // processors
16695  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16696 
16697  // loop over the nodes
16698  for (unsigned i = 0; i < n_global_nodes; i++)
16699  {
16700  // Get the names of the i-th global node
16701  Vector<Vector<unsigned>> global_inode_names = root_global_node_names[i];
16702  // Get the number of names for the i-th global node
16703  const unsigned n_names_global_inode = global_inode_names.size();
16704  // ... and store this info. to be sent from root to all
16705  // processors
16706  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16707  // loop over the names of the global i-th node
16708  for (unsigned j = 0; j < n_names_global_inode; j++)
16709  {
16710  // loop over the info. associated with each name
16711  for (unsigned k = 0; k < n_info_per_node_name; k++)
16712  {
16713  // Store the name info. of the current name in the
16714  // container to be sent from root to all processors
16715  flat_packed_root_send_receive_udata.push_back(
16716  global_inode_names[j][k]);
16717  } // for (k < n_info_per_node_name)
16718 
16719  } // for (j < n_names_inode)
16720 
16721  } // for (i < n_global_nodes)
16722 
16723  } // if (my_rank == root_processor)
16724 
16725  // ----------------------------------------------------------------
16726  // END: Unpackage the info. received on root. Compute the alias
16727  // of the nodes and prepare the info. to be sent back from
16728  // root to all processors
16729  // ----------------------------------------------------------------
16730 
16731  // ---------------------------------------------------------------
16732  // BEGIN: Send the info. back to all processors, unpackage the
16733  // info. and create the map from node name to global node
16734  // index
16735  // ---------------------------------------------------------------
16736  // The number of data that root send to other processors.
16737  unsigned root_n_udata_sent_to_all_proc =
16738  flat_packed_root_send_receive_udata.size();
16739 
16740  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16741  // receive
16742  1,
16743  MPI_UNSIGNED,
16744  root_processor,
16745  comm_pt->mpi_comm());
16746 
16747  // Resize the container if this is a processor that receives data
16748  if (my_rank != root_processor)
16749  {
16750  flat_packed_root_send_receive_udata.resize(root_n_udata_sent_to_all_proc);
16751  }
16752 
16753  // Send the info. from root and receive it on all processors
16754  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16755  // from root to
16756  // all
16757  // processors
16758  root_n_udata_sent_to_all_proc, // Number of data sent
16759  // from root to each
16760  // procesor
16761  MPI_UNSIGNED,
16762  root_processor, // The processor that sends all the info.
16763  comm_pt->mpi_comm());
16764 
16765  // Counter to extract the info.
16766  counter = 0;
16767  // Read the number of global nodes
16768  const unsigned n_global_nodes =
16769  flat_packed_root_send_receive_udata[counter++];
16770  // Store the global names of the nodes
16771  // global_node_name[x][ ][ ] Global node number
16772  // global_node_name[ ][x][ ] Global node names
16773  // global_node_name[ ][ ][x] Global node info.
16774  // Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16775  // Resize the input vector
16776  global_node_names.resize(n_global_nodes);
16777  // Now loop until all global nodes info. has been read
16778  unsigned n_read_global_nodes = 0;
16779  while (n_read_global_nodes < n_global_nodes)
16780  {
16781  // Read the number of names for the current global node
16782  const unsigned n_names_global_inode =
16783  flat_packed_root_send_receive_udata[counter++];
16784  // Counter for the global node
16785  const unsigned i = n_read_global_nodes;
16786  // Resize the container
16787  global_node_names[i].resize(n_names_global_inode);
16788  // loop over the names of the global inode
16789  for (unsigned j = 0; j < n_names_global_inode; j++)
16790  {
16791  // Resize the container
16792  global_node_names[i][j].resize(n_info_per_node_name);
16793  // loop over the info. of the j-th node name of the i-th
16794  // global node
16795  for (unsigned k = 0; k < n_info_per_node_name; k++)
16796  {
16797  // Read the k-th node info. from the j-th node name of
16798  // the i-th global node
16799  global_node_names[i][j][k] =
16800  flat_packed_root_send_receive_udata[counter++];
16801 
16802  } // for (k < n_info_per_node_name)
16803 
16804  // Create the map from the node name to the global node
16805  // index
16806  Vector<unsigned> node_name(n_info_per_node_name - 1);
16807  node_name[0] = global_node_names[i][j][0];
16808  node_name[1] = global_node_names[i][j][1];
16809  node_name[2] = global_node_names[i][j][2];
16810  node_name[3] = global_node_names[i][j][3];
16811  // Do not add the local index since it will not longer be
16812  // used. Additionally, we will not know the local node
16813  // index outside this method
16814  // node_name[4] = global_node_names[i][j][4];
16815  node_name_to_global_index[node_name] = i;
16816 
16817  } // for (j < n_names_global_inode)
16818 
16819  // Increase the counter for read global nodes
16820  n_read_global_nodes++;
16821 
16822  } // while (n_read_global_nodes < n_global_nodes)
16823 
16824 #ifdef PARANOID
16825  // Check we have read all the info.
16826  if (counter != root_n_udata_sent_to_all_proc)
16827  {
16828  std::ostringstream error_stream;
16829  error_stream
16830  << "The info. received from root regarding the global names of "
16831  << "the nodes\nwas not completely read.\n"
16832  << "The number of data sent/received from root is: ("
16833  << root_n_udata_sent_to_all_proc << ")\n"
16834  << "The number of data read from the received info. is: (" << counter
16835  << ")\n\n";
16836  throw OomphLibError(
16837  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16838  } // if (counter != root_n_udata_sent_to_all_proc)
16839 #endif
16840 
16841  // ---------------------------------------------------------------
16842  // END: Send the info. back to all processors, unpackage the info.
16843  // and create the map from node name to global node index
16844  // ---------------------------------------------------------------
16845 
16846  // ---------------------------------------------------------------
16847  // BEGIN: Add the info. from the global node names into the
16848  // info. of the local node names. We do this because the
16849  // local node names have pointers to the nodes.
16850  // Additionally, create a map from the node name to the
16851  // index of its global node
16852  // ---------------------------------------------------------------
16853 
16854  // Resize the global shared node pointers container
16855  global_shared_node_pt.resize(n_global_nodes, 0);
16856 
16857  // loop over the number of global nodes
16858  for (unsigned i = 0; i < n_global_nodes; i++)
16859  {
16860  // Flag to indicate that the iglobal node is part of the nodes
16861  // on the current processor
16862  bool is_this_a_local_node_name = false;
16863  unsigned local_node_number;
16864  // Get the number of names of the i-th global node
16865  const unsigned n_names_global_inode = global_node_names[i].size();
16866  // loop over the names of the i-th global node
16867  for (unsigned j = 0; j < n_names_global_inode; j++)
16868  {
16869  // Get the node name info.
16870  const unsigned iproc = global_node_names[i][j][0];
16871  local_node_number = global_node_names[i][j][4];
16872 
16873  // Check if this node name lives on this processor
16874  if (my_rank == iproc)
16875  {
16876  // The node is part of the local node names
16877  is_this_a_local_node_name = true;
16878  // Break
16879  break;
16880  } // if (my_rank == iproc)
16881 
16882  } // for (j < n_names_global_inode)
16883 
16884  // If the node is part of the local nodes then add the
16885  // additional names of the node in the local container
16886  if (is_this_a_local_node_name)
16887  {
16888 #ifdef PARANOID
16889  // Check that the global node include at least all the names
16890  // of the node on this processor
16891  const unsigned n_names_local_node =
16892  local_node_names[local_node_number].size();
16893  unsigned n_names_found_on_global_name_node = 0;
16894 #endif
16895 
16896  // Add the pointer of the node into the global shared node
16897  // pointers container
16898  global_shared_node_pt[i] = local_node_pt[local_node_number];
16899 
16900  // Add all the global names of the node onto the local node
16901  // names
16902 
16903  // loop again over the names of the i-th global node
16904  for (unsigned j = 0; j < n_names_global_inode; j++)
16905  {
16906  // Get the node name info.
16907  const unsigned iproc = global_node_names[i][j][0];
16908 
16909  // Is this a node name on this processor?
16910  if (iproc != my_rank)
16911  {
16912  // Add the name
16913  local_node_names[local_node_number].push_back(
16914  global_node_names[i][j]);
16915  }
16916 #ifdef PARANOID
16917  else
16918  {
16919  const unsigned jproc = global_node_names[i][j][1];
16920  const unsigned ishd_bnd = global_node_names[i][j][2];
16921  const unsigned idx = global_node_names[i][j][3];
16922  const unsigned n_local_node = global_node_names[i][j][4];
16923  // loop over the names of the local node
16924  for (unsigned k = 0; k < n_names_local_node; k++)
16925  {
16926  if ((local_node_names[local_node_number][k][0] == iproc) &&
16927  (local_node_names[local_node_number][k][1] == jproc) &&
16928  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16929  (local_node_names[local_node_number][k][3] == idx) &&
16930  (local_node_names[local_node_number][k][4] == n_local_node))
16931  {
16932  // Increase the number of local nodes found on the
16933  // global nodes
16934  n_names_found_on_global_name_node++;
16935  } // found global node on local nodes
16936 
16937  } // for (k < n_names_local_node)
16938 
16939  } // if (iproc != my_rank)
16940 #endif
16941 
16942  } // for (j < n_names_global_inode)
16943 
16944 #ifdef PARANOID
16945  // The number of local nodes names must be the same as the the
16946  // number of global nodes names associated with this processor
16947  // (my_rank, that start with iproc = my_rank)
16948  if (n_names_local_node != n_names_found_on_global_name_node)
16949  {
16950  std::ostringstream error_stream;
16951  error_stream << "The local node names corresponding to the local "
16952  << "node (" << local_node_number << ") were\n"
16953  << "not found on the global node names.\n\n"
16954  << "These are the names of the local node\n"
16955  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16956  for (unsigned k = 0; k < n_names_local_node; k++)
16957  {
16958  error_stream << "Name(" << k
16959  << "): " << local_node_names[local_node_number][k][0]
16960  << ", " << local_node_names[local_node_number][k][1]
16961  << ", " << local_node_names[local_node_number][k][2]
16962  << ", " << local_node_names[local_node_number][k][3]
16963  << ", " << local_node_names[local_node_number][k][4]
16964  << "\n";
16965  }
16966 
16967  error_stream << "\n\nThese are the names of the global node\n"
16968  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16969  for (unsigned k = 0; k < n_names_global_inode; k++)
16970  {
16971  error_stream << "Name(" << k << "): " << global_node_names[i][k][0]
16972  << ", " << global_node_names[i][k][1] << ", "
16973  << global_node_names[i][k][2] << ", "
16974  << global_node_names[i][k][3] << ", "
16975  << global_node_names[i][k][4] << "\n";
16976  }
16977 
16978  throw OomphLibError(error_stream.str(),
16979  OOMPH_CURRENT_FUNCTION,
16980  OOMPH_EXCEPTION_LOCATION);
16981  }
16982 #endif
16983 
16984  } // if (is_this_a_local_node_name)
16985 
16986  } // for (i < n_global_nodes)
16987 
16988  // ---------------------------------------------------------------
16989  // END: Add the info. from the global node names into the info.
16990  // of the local node names. We do this because the local
16991  // node names have pointers to the nodes
16992  // ---------------------------------------------------------------
16993 
16994  // ---------------------------------------------------------------
16995  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
16996  // the local nodes.
16997  // ---------------------------------------------------------------
16998 
16999  // Loop over the local nodes and fill the
17000  // other_proc_shd_bnd_node_pt container with the corresponding
17001  // info. NOTE: We are using the old size of the local node names,
17002  // before adding the names of the global nodes so we only loop
17003  // over the local nodes and not global.
17004 
17005  // Compute the local shared boudary id
17006  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
17007 
17008  // loop over the local nodes names
17009  for (unsigned i = 0; i < n_local_nodes; i++)
17010  {
17011  // Get the number of names for the i-th local node
17012  const unsigned n_names = local_node_names[i].size();
17013  // Get a pointer to the first name of the node found on this
17014  // processor (this ensures that the node lives on this
17015  // processor)
17016  Node* node_pt = local_node_pt[i];
17017  // loop over the names of the i-th local node and add an entry
17018  // to the other_proc_shd_bnd_node_pt structure
17019  for (unsigned j = 0; j < n_names; j++)
17020  {
17021  // Get the node name info.
17022  const unsigned iproc = local_node_names[i][j][0];
17023  const unsigned jproc = local_node_names[i][j][1];
17024  const unsigned ishd_bnd =
17025  local_node_names[i][j][2] - initial_shd_bnd_id;
17026  const unsigned index = local_node_names[i][j][3];
17027  // We can ignore the last entry, it was just used to compute
17028  // the global node number by the root processor
17029 
17030  // Get the smallest processor number
17031  if (iproc < jproc)
17032  {
17033  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index] = node_pt;
17034  }
17035  else
17036  {
17037  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index] = node_pt;
17038  }
17039 
17040  } // for (j < n_names)
17041 
17042  } // for (i < n_local_node_names)
17043 
17044  // ---------------------------------------------------------------
17045  // END: Fill the data structure other_proc_shd_bnd_node_pt with
17046  // the local nodes.
17047  // ---------------------------------------------------------------
17048  }
17049 
17050  //======================================================================
17051  // \short Get the original boundaries to which is associated each
17052  // shared node, and send the info. to the related processors. We
17053  // need to do this so that at the reset of halo(ed) info. stage,
17054  // the info. is updated
17055  template<class ELEMENT>
17057  Vector<Vector<Vector<unsigned>>>& global_node_names,
17058  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
17059  Vector<Node*>& global_shared_node_pt)
17060  {
17061  // Get the rank and number of processors
17062  const unsigned nproc = this->communicator_pt()->nproc();
17063  const unsigned my_rank = this->communicator_pt()->my_rank();
17064 
17065  // The number of nodes on shared boundaries
17066  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
17067  // ---------------------------------------------------------
17068  // BEGIN: Get the shared nodes between each of processors
17069  // ---------------------------------------------------------
17070 
17071  // Store the nodes on shared boundaries in this processor with other
17072  // processors
17073  Vector<std::set<Node*>> node_on_shd_bnd_pt(nproc);
17074 
17075  // A map to get access to the global shared node number from the
17076  // node pointer
17077  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
17078 
17079  // loop over the global nodes names and get only those in this
17080  // processor
17081  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
17082  {
17083  // Get the number of names of the current node on shared
17084  // boundaries
17085  const unsigned n_names = global_node_names[i].size();
17086  // loop over the names
17087  for (unsigned j = 0; j < n_names; j++)
17088  {
17089  // Store the node name
17090  Vector<unsigned> node_name(4);
17091  node_name[0] = global_node_names[i][j][0];
17092  node_name[1] = global_node_names[i][j][1];
17093  node_name[2] = global_node_names[i][j][2];
17094  node_name[3] = global_node_names[i][j][3];
17095 
17096  // Check whether the node is in the current processor
17097  if (node_name[0] == my_rank)
17098  {
17099  // Check with which processor the node is shared
17100  const unsigned jproc = node_name[1];
17101 
17102 #ifdef PARANOID
17103  std::map<Vector<unsigned>, unsigned>::iterator it =
17104  node_name_to_global_index.find(node_name);
17105  if (it != node_name_to_global_index.end())
17106  {
17107  // Check whether the global node index correspond with that
17108  // of the current global node name
17109  if (i != (*it).second)
17110  {
17111  std::ostringstream error_message;
17112  error_message
17113  << "The global node number " << (*it).second
17114  << ") obtained from the current node\n"
17115  << "name is not the same as the current node number (" << i
17116  << ").\n\n"
17117  << "Node name:\n"
17118  << "iproc:" << node_name[0] << "\n"
17119  << "jproc:" << node_name[1] << "\n"
17120  << "shd_bnd_id:" << node_name[2] << "\n"
17121  << "index:" << node_name[3] << "\n\n";
17122  throw OomphLibError(error_message.str(),
17123  OOMPH_CURRENT_FUNCTION,
17124  OOMPH_EXCEPTION_LOCATION);
17125  }
17126  }
17127  else
17128  {
17129  std::ostringstream error_message;
17130  error_message
17131  << "The node name is not registerd as living in this processor.\n"
17132  << "Node name:\n"
17133  << "iproc:" << node_name[0] << "\n"
17134  << "jproc:" << node_name[1] << "\n"
17135  << "shd_bnd_id:" << node_name[2] << "\n"
17136  << "index:" << node_name[3] << "\n\n";
17137  throw OomphLibError(error_message.str(),
17138  OOMPH_CURRENT_FUNCTION,
17139  OOMPH_EXCEPTION_LOCATION);
17140  }
17141 
17142 #endif // #ifdef PARANOID
17143 
17144  // Get the node pointer
17145  Node* node_pt = global_shared_node_pt[i];
17146 
17147 #ifdef PARANOID
17148  if (node_pt == 0)
17149  {
17150  std::ostringstream error_message;
17151  error_message << "There is not global shared node within this\n"
17152  << "global node number (" << i
17153  << "). The global shared\n"
17154  << "node pointer is null\n\n";
17155  throw OomphLibError(error_message.str(),
17156  OOMPH_CURRENT_FUNCTION,
17157  OOMPH_EXCEPTION_LOCATION);
17158  }
17159 #endif // #ifdef PARANOID
17160 
17161  // Add the node to the nodes on shared boundaries in this
17162  // processor
17163  node_on_shd_bnd_pt[jproc].insert(node_pt);
17164 
17165  // And store the global node index
17166  node_pt_to_global_shd_bnd_index[node_pt] = i;
17167 
17168  } // if (node_name[0]==my_rank)
17169  else if (node_name[1] == my_rank)
17170  {
17171  // Check with which processor the node is shared
17172  const unsigned jproc = node_name[0];
17173 
17174 #ifdef PARANOID
17175  std::map<Vector<unsigned>, unsigned>::iterator it =
17176  node_name_to_global_index.find(node_name);
17177  if (it != node_name_to_global_index.end())
17178  {
17179  // Check whether the global node index correspond with that
17180  // of the current global node name
17181  if (i != (*it).second)
17182  {
17183  std::ostringstream error_message;
17184  error_message
17185  << "The global node number " << (*it).second
17186  << ") obtained from the current node\n"
17187  << "name is not the same as the current node number (" << i
17188  << ").\n\n"
17189  << "Node name:\n"
17190  << "iproc:" << node_name[0] << "\n"
17191  << "jproc:" << node_name[1] << "\n"
17192  << "shd_bnd_id:" << node_name[2] << "\n"
17193  << "index:" << node_name[3] << "\n\n";
17194  throw OomphLibError(error_message.str(),
17195  OOMPH_CURRENT_FUNCTION,
17196  OOMPH_EXCEPTION_LOCATION);
17197  }
17198  }
17199  else
17200  {
17201  std::ostringstream error_message;
17202  error_message
17203  << "The node name is not registerd as living in this processor.\n"
17204  << "Node name:\n"
17205  << "iproc:" << node_name[0] << "\n"
17206  << "jproc:" << node_name[1] << "\n"
17207  << "shd_bnd_id:" << node_name[2] << "\n"
17208  << "index:" << node_name[3] << "\n\n";
17209  throw OomphLibError(error_message.str(),
17210  OOMPH_CURRENT_FUNCTION,
17211  OOMPH_EXCEPTION_LOCATION);
17212  }
17213 
17214 #endif // #ifdef PARANOID
17215 
17216  // Get the node pointer
17217  Node* node_pt = global_shared_node_pt[i];
17218 
17219 #ifdef PARANOID
17220  if (node_pt == 0)
17221  {
17222  std::ostringstream error_message;
17223  error_message << "There is not global shared node within this\n"
17224  << "global node number (" << i
17225  << "). The global shared\n"
17226  << "node pointer is null\n\n";
17227  throw OomphLibError(error_message.str(),
17228  OOMPH_CURRENT_FUNCTION,
17229  OOMPH_EXCEPTION_LOCATION);
17230  }
17231 #endif // #ifdef PARANOID
17232 
17233  // Add the node to the nodes on shared boundaries in this
17234  // processor
17235  node_on_shd_bnd_pt[jproc].insert(node_pt);
17236 
17237  // And store the global node index
17238  node_pt_to_global_shd_bnd_index[node_pt] = i;
17239  }
17240 
17241  } // for (j < n_names)
17242 
17243  } // for (i < n_nodes_on_shd_bnds)
17244 
17245  // ---------------------------------------------------------
17246  // END: Get the shared nodes between each of processors
17247  // ---------------------------------------------------------
17248 
17249  // ---------------------------------------------------------
17250  // BEGIN: Get the original boundaries associated to each
17251  // node on a shared boundary
17252  // ---------------------------------------------------------
17253 
17254  // Store the global shared node number
17255  Vector<Vector<unsigned>> global_node_on_shared_bound(nproc);
17256  // Store the boundaries associated with the global shared node
17257  // number
17258  Vector<Vector<Vector<unsigned>>> global_node_original_boundaries(nproc);
17259  // Store the zeta boundary coordinate of the nodes on original
17260  // boundaries
17261  Vector<Vector<Vector<double>>> global_node_zeta_coordinate(nproc);
17262 
17263  // loop over the processors
17264  for (unsigned iproc = 0; iproc < nproc; iproc++)
17265  {
17266  // Get the nodes added to be shared with the iproc processor
17267  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17268 
17269  // loop over the nodes
17270  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17271  it != nodes_shared_pt.end();
17272  it++)
17273  {
17274  // Get the node
17275  Node* node_pt = (*it);
17276  // Store the boundaries on which it is stored
17277  Vector<unsigned> on_original_boundaries;
17278  // For each boundary get the corresponding z value of the node
17279  // on the boundary
17280  Vector<double> zeta_coordinate;
17281  // Get the number of boudandaries
17282  const unsigned n_bnd = this->initial_shared_boundary_id();
17283  // loop over the boundaries and register the boundaries to which
17284  // it is associated
17285  for (unsigned bb = 0; bb < n_bnd; bb++)
17286  {
17287  // Is the node on original boundary bb?
17288  if (node_pt->is_on_boundary(bb))
17289  {
17290  // Then save it as being on boundary bb
17291  on_original_boundaries.push_back(bb);
17292  // Get the boundary coordinate
17293  Vector<double> zeta(1);
17294  node_pt->get_coordinates_on_boundary(bb, zeta);
17295  // Save the boundary coordinate
17296  zeta_coordinate.push_back(zeta[0]);
17297  }
17298 
17299  } // for (bb < n_bnd)
17300 
17301  // Is the node on an original boundary
17302  if (on_original_boundaries.size() > 0)
17303  {
17304  // Get the global shared node number
17305  std::map<Node*, unsigned>::iterator it_index =
17306  node_pt_to_global_shd_bnd_index.find(node_pt);
17307 #ifdef PARANOID
17308  if (it_index == node_pt_to_global_shd_bnd_index.end())
17309  {
17310  std::ostringstream error_message;
17311  error_message
17312  << "We could not find the global shared node index associated\n"
17313  << "with the node pointer with vertices coordinates:\n"
17314  << "(" << node_pt->x(0) << ", " << node_pt->x(1) << ")\n\n";
17315  throw OomphLibError(error_message.str(),
17316  OOMPH_CURRENT_FUNCTION,
17317  OOMPH_EXCEPTION_LOCATION);
17318  }
17319 #endif
17320  // The global shared node index
17321  const unsigned global_shared_node_number = (*it_index).second;
17322  // Store the global shared node number
17323  global_node_on_shared_bound[iproc].push_back(
17324  global_shared_node_number);
17325  // And store the original boundaries to which it is associated
17326  global_node_original_boundaries[iproc].push_back(
17327  on_original_boundaries);
17328  // and the corresponding zeta coordinate
17329  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17330  }
17331 
17332  } // loop over nodes on shared boundaries with iproc
17333 
17334  } // for (iproc < nproc)
17335 
17336  // ---------------------------------------------------------
17337  // END: Get the original boundaries associated to each
17338  // node on a shared boundary
17339  // ---------------------------------------------------------
17340 
17341  // ---------------------------------------------------------
17342  // BEGIN: Send the info. to the corresponding processors,
17343  // package the info, send it and receive it in the
17344  // corresponding processor, unpackage and set the
17345  // boundaries associated with the received nodes
17346  // ---------------------------------------------------------
17347 
17348  // Get the communicator of the mesh
17349  OomphCommunicator* comm_pt = this->communicator_pt();
17350 
17351  // Set MPI info
17352  MPI_Status status;
17353  MPI_Request request;
17354 
17355  // loop over the processors
17356  for (unsigned iproc = 0; iproc < nproc; iproc++)
17357  {
17358  // The number of nodes shared between the pair of processors
17359  const unsigned n_shd_nodes_my_rank_iproc =
17360  node_on_shd_bnd_pt[iproc].size();
17361 
17362  // Are there shared nodes between these pair of processors
17363  // (my_rank, iproc)? Also ensure not to send info. within myself
17364  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17365  {
17366  // The flat package to send the info, to the iproc processor
17367  Vector<unsigned> flat_package_unsigned_send;
17368  // The very first entry is the number of nodes shared by the
17369  // pair of processors (my_rank, iproc)
17370  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17371 
17372  // Get the number of shared nodes on original boundaries
17373  const unsigned n_global_shared_node_on_original_boundary =
17374  global_node_on_shared_bound[iproc].size();
17375 
17376  // The second data is the number of shared nodes on original
17377  // boundaries
17378  flat_package_unsigned_send.push_back(
17379  n_global_shared_node_on_original_boundary);
17380 
17381  // ... also send the zeta coordinates associated with the
17382  // original boundaries
17383  Vector<double> flat_package_double_send;
17384 
17385  // loop over the nodes shared between this pair of processors
17386  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17387  {
17388  // Get the global shared node index
17389  const unsigned global_shared_node_index =
17390  global_node_on_shared_bound[iproc][i];
17391 
17392  // Put in the package the shared node index of the current
17393  // node
17394  flat_package_unsigned_send.push_back(global_shared_node_index);
17395 
17396  // Get the original boundaries to which the node is associated
17397  Vector<unsigned> on_original_boundaries =
17398  global_node_original_boundaries[iproc][i];
17399 
17400  // Get the associated zeta boundary coordinates
17401  Vector<double> zeta_coordinate =
17402  global_node_zeta_coordinate[iproc][i];
17403 
17404  // Get the number of original boundaries to which the node is
17405  // associated
17406  const unsigned n_original_boundaries = on_original_boundaries.size();
17407 
17408  // Put in the package the number of original boundaries the
17409  // node is associated
17410  flat_package_unsigned_send.push_back(n_original_boundaries);
17411 
17412  // loop over the original boundaries ids and include them in
17413  // the package
17414  for (unsigned j = 0; j < n_original_boundaries; j++)
17415  {
17416  // Put in the package each of the original boundaries to
17417  // which it is associated
17418  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17419  // The zeta coordinate on the boundary
17420  flat_package_double_send.push_back(zeta_coordinate[j]);
17421  } // for (j < n_original_boundaries)
17422 
17423  } // for (i < n_global_shared_node_on_original_boundary)
17424 
17425  // Send data UNSIGNED -----------------------------------------
17426  // Get the size of the package to communicate to the iproc
17427  // processor
17428  const unsigned n_udata_send = flat_package_unsigned_send.size();
17429  int n_udata_send_int = n_udata_send;
17430 
17431  // Send/receive data to/from iproc processor
17432  MPI_Isend(&n_udata_send_int,
17433  1,
17434  MPI_UNSIGNED,
17435  iproc,
17436  1,
17437  comm_pt->mpi_comm(),
17438  &request);
17439 
17440  int n_udata_received_int = 0;
17441  MPI_Recv(&n_udata_received_int,
17442  1,
17443  MPI_UNSIGNED,
17444  iproc,
17445  1,
17446  comm_pt->mpi_comm(),
17447  &status);
17448  MPI_Wait(&request, MPI_STATUS_IGNORE);
17449 
17450  if (n_udata_send != 0)
17451  {
17452  MPI_Isend(&flat_package_unsigned_send[0],
17453  n_udata_send,
17454  MPI_UNSIGNED,
17455  iproc,
17456  2,
17457  comm_pt->mpi_comm(),
17458  &request);
17459  }
17460 
17461  const unsigned n_udata_received =
17462  static_cast<unsigned>(n_udata_received_int);
17463 
17464  // Where to receive the data from the iproc processor
17465  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17466 
17467  if (n_udata_received != 0)
17468  {
17469  MPI_Recv(&flat_package_unsigned_receive[0],
17470  n_udata_received,
17471  MPI_UNSIGNED,
17472  iproc,
17473  2,
17474  comm_pt->mpi_comm(),
17475  &status);
17476  }
17477 
17478  if (n_udata_send != 0)
17479  {
17480  MPI_Wait(&request, MPI_STATUS_IGNORE);
17481  }
17482 
17483  // Send data DOUBLE -----------------------------------------
17484  // Get the size of the package to communicate to the iproc
17485  // processor
17486  const unsigned n_ddata_send = flat_package_double_send.size();
17487  int n_ddata_send_int = n_ddata_send;
17488 
17489  // Send/receive data to/from iproc processor
17490  MPI_Isend(&n_ddata_send_int,
17491  1,
17492  MPI_UNSIGNED,
17493  iproc,
17494  1,
17495  comm_pt->mpi_comm(),
17496  &request);
17497 
17498  int n_ddata_received_int = 0;
17499  MPI_Recv(&n_ddata_received_int,
17500  1,
17501  MPI_UNSIGNED,
17502  iproc,
17503  1,
17504  comm_pt->mpi_comm(),
17505  &status);
17506  MPI_Wait(&request, MPI_STATUS_IGNORE);
17507 
17508  if (n_ddata_send != 0)
17509  {
17510  MPI_Isend(&flat_package_double_send[0],
17511  n_ddata_send,
17512  MPI_DOUBLE,
17513  iproc,
17514  2,
17515  comm_pt->mpi_comm(),
17516  &request);
17517  }
17518 
17519  const unsigned n_ddata_received =
17520  static_cast<unsigned>(n_ddata_received_int);
17521 
17522  // Where to receive the data from the iproc processor
17523  Vector<double> flat_package_double_receive(n_ddata_received);
17524 
17525  if (n_ddata_received != 0)
17526  {
17527  MPI_Recv(&flat_package_double_receive[0],
17528  n_ddata_received,
17529  MPI_DOUBLE,
17530  iproc,
17531  2,
17532  comm_pt->mpi_comm(),
17533  &status);
17534  }
17535 
17536  if (n_ddata_send != 0)
17537  {
17538  MPI_Wait(&request, MPI_STATUS_IGNORE);
17539  }
17540 
17541  // Unpackage -------------------------------------------------
17542  // ... and associate the nodes to the corresponding original
17543  // boundaries
17544 
17545  // The number of nodes to be received
17546  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17547 
17548  // Increase and decrease the number of received shared nodes to
17549  // avoid the warning when compiling without PARANOID
17550  n_shared_nodes_received++;
17551  n_shared_nodes_received--;
17552 
17553 #ifdef PARANOID
17554  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17555  {
17556  std::ostringstream error_message;
17557  error_message
17558  << "The number of shared nodes between the pair of processors is\n"
17559  << "not the same\n"
17560  << "N.shared nodes proc (" << my_rank << ") with proc (" << iproc
17561  << "): (" << n_shd_nodes_my_rank_iproc << "\n"
17562  << "N.shared nodes proc (" << iproc << ") with proc (" << my_rank
17563  << "): (" << n_shared_nodes_received << "\n\n"
17564  << "You should have got the same error in proc: (" << iproc
17565  << ")\n\n";
17566  throw OomphLibError(error_message.str(),
17567  OOMPH_CURRENT_FUNCTION,
17568  OOMPH_EXCEPTION_LOCATION);
17569  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17570 #endif
17571 
17572  // Skip the number of nodes on shared boundaries on original
17573  // boundaries received (that is why next lines are commented)
17574 
17575  // The number of nodes on shared boundaries on original
17576  // boundaries
17577  // const unsigned n_shared_nodes_on_original_boundaries_received =
17578  // flat_package_unsigned_receive[1];
17579 
17580  // loop over the received info.
17581  unsigned current_index_data = 2;
17582  unsigned current_index_ddata = 0;
17583  while (current_index_data < n_udata_received)
17584  {
17585  // The global shared node number
17586  const unsigned global_shared_node_index =
17587  flat_package_unsigned_receive[current_index_data++];
17588 
17589  // The pointer to the node
17590  Node* node_pt = 0;
17591 
17592  // The number of original boundaries the node is associated
17593  // with
17594  const unsigned n_original_boundaries =
17595  flat_package_unsigned_receive[current_index_data++];
17596 
17597  // Get the node pointer
17598  node_pt = global_shared_node_pt[global_shared_node_index];
17599 #ifdef PARANOID
17600  if (node_pt == 0)
17601  {
17602  std::ostringstream error_message;
17603  error_message
17604  << "The global shared node (" << global_shared_node_index << ") "
17605  << "could not be found in this processor!!!\n"
17606  << "However, it was found in processor (" << iproc << "). The "
17607  << "data may be no synchronised,\ntherefore "
17608  << "we may be looking for a global shared node number that "
17609  << "do not\ncorrespond with the one that was sent by "
17610  << "processor (" << iproc << ")\n\n";
17611  throw OomphLibError(error_message.str(),
17612  OOMPH_CURRENT_FUNCTION,
17613  OOMPH_EXCEPTION_LOCATION);
17614  }
17615 #endif // #ifdef PARANOID
17616 
17617  // loop over the number of original boundaries and associate
17618  // the node to each of those boundaries
17619  for (unsigned i = 0; i < n_original_boundaries; i++)
17620  {
17621  // Get the original boundary to which the node is associated
17622  // with
17623  const unsigned original_bound_id =
17624  flat_package_unsigned_receive[current_index_data++];
17625 
17626  // Associate the node with the boundary
17627  this->add_boundary_node(original_bound_id, node_pt);
17628 
17629  // Get the zeta boundary coordinate
17630  Vector<double> zeta(1);
17631  zeta[0] = flat_package_double_receive[current_index_ddata++];
17632  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17633  }
17634 
17635  } // while(current_data < n_data_received)
17636 
17637  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17638 
17639  } // for (iproc < nproc)
17640 
17641  // ---------------------------------------------------------
17642  // END: Send the info. to the corresponding processors,
17643  // package the info, send it and receive it in the
17644  // corresponding processor, unpackage and set the
17645  // boundaries associated with the received nodes
17646  // ---------------------------------------------------------
17647  }
17648 
17649  //======================================================================
17650  // \short In charge of creating additional halo(ed) elements on those
17651  // processors that have no shared boundaries in common but have
17652  // shared nodes
17653  // ======================================================================
17654  template<class ELEMENT>
17656  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
17657  other_proc_shd_bnd_node_pt,
17658  Vector<Vector<Node*>>& iproc_currently_created_nodes_pt,
17659  Vector<Vector<Vector<unsigned>>>& global_node_names,
17660  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
17661  Vector<Node*>& global_shared_node_pt)
17662  {
17663  // Get the rank and number of processors
17664  const unsigned nproc = this->communicator_pt()->nproc();
17665  const unsigned my_rank = this->communicator_pt()->my_rank();
17666 
17667  // ---------------------------------------------------------------
17668  // BEGIN: Create a map to check whether a node is on the global
17669  // shared nodes. Also set a map to obtain the global
17670  // shared node index (this index is the same as the global
17671  // node name)
17672  // ---------------------------------------------------------------
17673  std::map<Node*, bool> is_global_shared_node;
17674  std::map<Node*, unsigned> global_shared_node_index;
17675 
17676  // Get the number of global shared nodes
17677  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17678  // loop over the global shared nodes
17679  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17680  {
17681  // Get the node
17682  Node* node_pt = global_shared_node_pt[i];
17683  // Indicate this is a shared global node
17684  is_global_shared_node[node_pt] = true;
17685  // Set the map to obtain the index of the global shared node
17686  global_shared_node_index[node_pt] = i;
17687 
17688  } // for (i < n_global_shared_nodes)
17689 
17690  // ---------------------------------------------------------------
17691  // END: Create a map to check whether a node is on the global
17692  // shared nodes. Also set a map to obtain the global
17693  // shared node index (this index is the same as the global
17694  // node name)
17695  // ---------------------------------------------------------------
17696 
17697  // ---------------------------------------------------------------
17698  // BEGIN: Loop over the haloed elements and check whether the nodes
17699  // on the haloed elements are part of the global shared
17700  // nodes. If that is the case then check whether the
17701  // element should be sent to the processors with which the
17702  // node is shared
17703  // ---------------------------------------------------------------
17704 
17705  // Elements that may be sent to other processors
17706  Vector<std::set<GeneralisedElement*>> additional_elements_pt(nproc);
17707 
17708  // loop over the processors
17709  for (unsigned iproc = 0; iproc < nproc; iproc++)
17710  {
17711  if (iproc != my_rank)
17712  {
17713  // Get the haloed element with iproc
17714  Vector<GeneralisedElement*> haloed_ele_pt =
17715  this->root_haloed_element_pt(iproc);
17716 
17717  // Get the number of haloed elements
17718  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17719 
17720  // loop over the haloed elements with iproc
17721  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17722  {
17723  // A pointer to the generalised element
17724  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17725  // Get the finite element representation of the element
17726  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17727  // Get the number of nodes
17728  const unsigned n_nodes = ele_pt->nnode();
17729  // loop over the nodes of the element
17730  for (unsigned n = 0; n < n_nodes; n++)
17731  {
17732  // Get the node
17733  Node* node_pt = ele_pt->node_pt(n);
17734  // Is the node a global shared node?
17735  if (is_global_shared_node[node_pt])
17736  {
17737  // Get the index of the global shared node
17738  const unsigned global_index = global_shared_node_index[node_pt];
17739  // Get the global names of the node
17740  Vector<Vector<unsigned>> iglobal_names =
17741  global_node_names[global_index];
17742 
17743  // Get the number of names
17744  const unsigned n_names = iglobal_names.size();
17745  // loop over the names and check which processors share
17746  // this node (the processors to which the element may be
17747  // sent
17748  for (unsigned j = 0; j < n_names; j++)
17749  {
17750  // Get the processors to which the element should be
17751  // sent
17752  const unsigned proc1 = iglobal_names[j][0];
17753  const unsigned proc2 = iglobal_names[j][1];
17754  // Add the element to the set of additional elements to
17755  // sent from proc1 to proc2
17756  additional_elements_pt[proc1].insert(gele_pt);
17757  additional_elements_pt[proc2].insert(gele_pt);
17758 
17759  } // for (j < n_names)
17760 
17761  } // if (is_global_shared_node[node_pt])
17762 
17763  } // for (n < n_nodes)
17764 
17765  } // for (ihd < n_haloed_ele)
17766 
17767  } // if (iproc!=my_rank)
17768 
17769  } // for (iproc < nproc)
17770 
17771  // ---------------------------------------------------------------
17772  // Now check whether the element should really be sent to the
17773  // indicated processors
17774 
17775  // The elements from this (my_rank) processor that will be sent to
17776  // other processors
17777  Vector<Vector<FiniteElement*>> send_haloed_ele_pt(nproc);
17778 
17779  // loop over the processors
17780  for (unsigned iproc = 0; iproc < nproc; iproc++)
17781  {
17782  if (iproc != my_rank)
17783  {
17784  // Get the set of element that may be sent to the iproc
17785  // processor
17786  std::set<GeneralisedElement*> iproc_ele_pt =
17787  additional_elements_pt[iproc];
17788  // loop over the element that may be sent to the iproc
17789  // processor
17790  for (std::set<GeneralisedElement*>::iterator it = iproc_ele_pt.begin();
17791  it != iproc_ele_pt.end();
17792  it++)
17793  {
17794  // Get a pointer to the element
17795  GeneralisedElement* gele_pt = (*it);
17796 
17797  // Get the haloed element with iproc
17798  Vector<GeneralisedElement*> haloed_ele_pt =
17799  this->root_haloed_element_pt(iproc);
17800 
17801  // Get the number of haloed elements
17802  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17803 
17804  // Flag to indicate whether the element has been already sent
17805  // to the iproc processor
17806  bool send_ele_to_iproc_processor = true;
17807  // loop over the haloed elements with iproc and check whether
17808  // the element has been already sent to iproc (if it is
17809  // already a haloed element with iproc then it has been
17810  // already sent)
17811  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17812  {
17813  // A pointer to the generalised element
17814  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17815  if (gele_pt == ghd_ele_pt)
17816  {
17817  // Mark the element as not required to be sent
17818  send_ele_to_iproc_processor = false;
17819  // Break the loop that searchs for the element on the
17820  // haloed elements with iproc
17821  break;
17822  }
17823 
17824  } // for (ihd < n_haloed_ele)
17825 
17826  // Do we need to sent the element?
17827  if (send_ele_to_iproc_processor)
17828  {
17829  // Get the finite element representation of the element
17830  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17831  // Add the element to those that will be sent to the iproc
17832  // processor
17833  send_haloed_ele_pt[iproc].push_back(ele_pt);
17834  }
17835 
17836  } // loop over the elements that may be sent to the iproc
17837  // processor
17838 
17839  } // if (iproc!=my_rank)
17840 
17841  } // for (iproc < nproc)
17842 
17843  // ---------------------------------------------------------------
17844  // END: Loop over the haloed element and check whether the nodes
17845  // on the haloed elements are part of the global shared
17846  // nodes. If that is the case then check whether the element
17847  // should be sent to the processors with which the node is
17848  // shared
17849  // ---------------------------------------------------------------
17850 
17851  // ============================================================
17852  // Now send the additional elements
17853  // ============================================================
17854  // Loop over the processors to send data
17855  for (unsigned iproc = 0; iproc < nproc; iproc++)
17856  {
17857  // There are no elements to send with myself
17858  if (iproc != my_rank)
17859  {
17860  // Get the number of additional haloed elements to send
17861  const unsigned n_additional_haloed_ele =
17862  send_haloed_ele_pt[iproc].size();
17863 
17864  // Clear send and receive buffers
17865  Flat_packed_unsigneds.clear();
17866  Flat_packed_doubles.clear();
17867 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17868  Flat_packed_unsigneds_string.clear();
17869 #endif
17870 
17871  // The very first data of the flat packed is the number of
17872  // additional haloed elements, this will be the number of
17873  // additional halo elements to create on the receiver processor
17874  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17875 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17876  std::stringstream junk;
17877  junk << "Number of haloed elements " << nhaloed_ele;
17878  Flat_packed_unsigneds_string.push_back(junk.str());
17879 #endif
17880 
17881  // Loop over the additioanl haloed elements
17882  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17883  {
17884  // Get pointer to the additional haloed element
17885  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17886  const unsigned nroot_haloed_ele = this->nroot_haloed_element(iproc);
17887 
17888  // Check if the element has been already added to the
17889  // halo(ed) scheme
17890 
17891  // Get the generalised version of the element
17892  GeneralisedElement* gen_ele_pt = ele_pt;
17893  // Try to add the haloed element
17894  const unsigned haloed_ele_index =
17895  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17896 
17897  // Was the element added or only returned the index of the
17898  // element
17899  if (nroot_haloed_ele == haloed_ele_index)
17900  {
17901  Flat_packed_unsigneds.push_back(1);
17902 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17903  Flat_packed_unsigneds_string.push_back(
17904  "Haloed element needs to be constructed");
17905 #endif
17906 
17907  // Get additional info. related with the haloed element
17908  get_required_elemental_information_helper(iproc, ele_pt);
17909 
17910  // Get the nodes on the element
17911  const unsigned nnodes = ele_pt->nnode();
17912  for (unsigned j = 0; j < nnodes; j++)
17913  {
17914  Node* node_pt = ele_pt->node_pt(j);
17915 
17916  // Package the info. of the nodes
17917  // The destination processor goes in the arguments
17918  add_haloed_node_helper(iproc, node_pt);
17919 
17920  } // for (j < nnodes)
17921 
17922  } // add the element and send its nodes
17923  else // The haloed element already exists
17924  {
17925  Flat_packed_unsigneds.push_back(0);
17926 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17927  Flat_packed_unsigneds_string.push_back(
17928  "Haloed element already exists");
17929 #endif
17930  Flat_packed_unsigneds.push_back(haloed_ele_index);
17931 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17932  Flat_packed_unsigneds_string.push_back(
17933  "Index of existing haloed element");
17934 #endif
17935  } // else (next_haloed_ele == external_haloed_ele_index)
17936 
17937  } // for (e < n_additional_haloed_ele)
17938 
17939  // Send and received the additional haloed elements (all
17940  // processors send and receive)
17941 
17942  // The processor to which send the elements
17943  int send_proc = static_cast<int>(iproc);
17944  // The processor from which receive the elements
17945  int recv_proc = static_cast<int>(iproc);
17946  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17947 
17948  // Reset the counters
17949  Counter_for_flat_packed_doubles = 0;
17950  Counter_for_flat_packed_unsigneds = 0;
17951 
17952  // Get the number of additional halo element to be created
17953  const unsigned n_additional_halo_ele =
17954  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
17955 
17956 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17957  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
17958  << " Number of elements need to be constructed "
17959  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
17960  << std::endl;
17961 #endif
17962 
17963  // Create the additional halo elements
17964  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17965  {
17966  // Create halo element from received info. of "iproc"
17967  // processor on the current processor
17968  create_halo_element(iproc,
17969  iproc_currently_created_nodes_pt[iproc],
17970  other_proc_shd_bnd_node_pt,
17971  global_node_names,
17972  node_name_to_global_index,
17973  global_shared_node_pt);
17974 
17975  } // for (e < n_additional_halo_ele)
17976 
17977  } // if (iproc != my_rank)
17978 
17979  } // for (iproc < nproc)
17980  }
17981 
17982  // *********************************************************************
17983  // Start communication functions
17984  // *********************************************************************
17985 
17986  //========start of get_required_elemental_information_helper==============
17987  /// \short Helper function to get the required elemental information from
17988  /// an haloed element. This info. involves the association of the element
17989  /// to a boundary or region.
17990  //========================================================================
17991  template<class ELEMENT>
17993  ELEMENT>::get_required_elemental_information_helper(unsigned& iproc,
17994  FiniteElement* ele_pt)
17995  {
17996  // Check if the element is associated with the original boundaries
17997  const unsigned nbound = this->initial_shared_boundary_id();
17998 
17999  // ------------------------------------------------------------------
18000  // Stores the information regarding the boundaries associated to the
18001  // element (it that is the case)
18002  Vector<unsigned> associated_boundaries;
18003  Vector<unsigned> face_index_on_boundary;
18004 
18005  unsigned counter_face_indexes = 0;
18006 
18007  for (unsigned b = 0; b < nbound; b++)
18008  {
18009  // Get the number of elements associated to boundary i
18010  const unsigned nboundary_ele = nboundary_element(b);
18011  for (unsigned e = 0; e < nboundary_ele; e++)
18012  {
18013  if (ele_pt == this->boundary_element_pt(b, e))
18014  {
18015  // Keep track of the boundaries associated to the element
18016  associated_boundaries.push_back(b);
18017  // Get the face index
18018  face_index_on_boundary.push_back(face_index_at_boundary(b, e));
18019  counter_face_indexes++;
18020 #ifdef PARANOID
18021  if (counter_face_indexes > 2)
18022  {
18023  std::stringstream error_message;
18024  error_message
18025  << "A triangular element can not have more than two of its faces "
18026  << "on a boundary!!!\n\n";
18027  throw OomphLibError(error_message.str(),
18028  OOMPH_CURRENT_FUNCTION,
18029  OOMPH_EXCEPTION_LOCATION);
18030  }
18031 #else
18032  // Already found 2 face indexes on the same boundary?
18033  if (counter_face_indexes == 2)
18034  {
18035  break;
18036  }
18037 #endif // #ifdef PARANOID
18038 
18039  } // if (ele_pt == this->boundary_element_pt(b,e))
18040 
18041  } // (e < nboundary_ele)
18042 
18043  } // (b < nbound)
18044 
18045  // If the element is associated to any boundary then package all the
18046  // relevant info
18047  const unsigned nassociated_boundaries = associated_boundaries.size();
18048  if (nassociated_boundaries > 0)
18049  {
18050  Flat_packed_unsigneds.push_back(1);
18051 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18052  Flat_packed_unsigneds_string.push_back(
18053  "The element is a boundary element");
18054 #endif
18055  Flat_packed_unsigneds.push_back(nassociated_boundaries);
18056 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18057  std::stringstream junk;
18058  junk << "The elements is associated to " << nassociated_boundaries
18059  << " boundaries";
18060  Flat_packed_unsigneds_string.push_back(junk.str());
18061 #endif
18062 
18063  // Package the ids of the associated boundaries and the
18064  // corresponding face index for each boundary (if the element is a
18065  // corner element, it will have two faces associated to the
18066  // boundary)
18067  for (unsigned i = 0; i < nassociated_boundaries; i++)
18068  {
18069  unsigned b = associated_boundaries[i];
18070  Flat_packed_unsigneds.push_back(b);
18071 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18072  std::stringstream junk;
18073  junk << "Element associated to boundary " << b << " of "
18074  << nassociated_boundaries << " total associated boundaries";
18075  Flat_packed_unsigneds_string.push_back(junk.str());
18076 #endif
18077  unsigned f = face_index_on_boundary[i];
18078  Flat_packed_unsigneds.push_back(f);
18079 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18080  std::stringstream junk2;
18081  junk2 << "Face index " << f << " for associated boundary " << b;
18082  Flat_packed_unsigneds_string.push_back(junk2.str());
18083 #endif
18084  }
18085 
18086  // If the element is associated to any boundary then we should
18087  // check if the mesh has regions, if that is the case then we need
18088  // to check to which region the boundary element does belong
18089 
18090  // If the mesh has regions we should look for the element
18091  // associated to a boundary and a specified region
18092  Vector<Vector<unsigned>> associated_boundaries_and_regions;
18093  Vector<unsigned> face_index_on_boundary_and_region;
18094 
18095  // Now check for the case when we have regions in the mesh
18096  const unsigned n_regions = this->nregion();
18097  if (n_regions > 1)
18098  {
18099  // Used to count the number of faces associated with
18100  // boundary-regions
18101  unsigned counter_face_indexes_in_regions = 0;
18102  // Loop over the boundaries
18103  for (unsigned b = 0; b < nbound; b++)
18104  {
18105  // Go through each region by getting the region id
18106  for (unsigned i_reg = 0; i_reg < n_regions; i_reg++)
18107  {
18108  // Get thre region id associated with the (i_reg)-th region
18109  const unsigned region_id =
18110  static_cast<unsigned>(this->Region_attribute[i_reg]);
18111 
18112  // Loop over all elements associated with the current boundary
18113  // and the i_reg-th region and check if the element is part of
18114  // any region
18115  const unsigned nele_in_region =
18116  this->nboundary_element_in_region(b, region_id);
18117  for (unsigned ee = 0; ee < nele_in_region; ee++)
18118  {
18119  // Check if the boundary-region element is the same as the
18120  // element
18121  if (ele_pt ==
18122  this->boundary_element_in_region_pt(b, region_id, ee))
18123  {
18124  // Storage for the boundary and region associated to the
18125  // element
18126  Vector<unsigned> bound_and_region(2);
18127 
18128  // Keep track of the boundaries associated to the element
18129  bound_and_region[0] = b;
18130  // Keep track of the regions associated to the element
18131  bound_and_region[1] = region_id;
18132  // Add the boundaries and regions in the storage to be
18133  // sent to other processors
18134  associated_boundaries_and_regions.push_back(bound_and_region);
18135  // Get the face index and keep track of it
18136  face_index_on_boundary_and_region.push_back(
18137  this->face_index_at_boundary_in_region(b, region_id, ee));
18138 
18139  // Increase the number of faces of the element associated
18140  // to boundary-regions
18141  counter_face_indexes_in_regions++;
18142 
18143 #ifdef PARANOID
18144  if (counter_face_indexes_in_regions > 2)
18145  {
18146  std::stringstream error_message;
18147  error_message << "A triangular element can not have more "
18148  "than two of its\n"
18149  << "faces on a boundary!!!\n\n";
18150  throw OomphLibError(error_message.str(),
18151  OOMPH_CURRENT_FUNCTION,
18152  OOMPH_EXCEPTION_LOCATION);
18153  } // if (counter_face_indexes_in_regions > 2)
18154 #endif
18155 
18156  } // The element is a boundary-region element
18157 
18158  } // for (ee < nele_in_region)
18159 
18160  } // for (i_reg < n_regions)
18161 
18162  } // for (b < nbound)
18163 
18164  } // if (n_regions > 1)
18165 
18166  // Now package the info. to be sent to other processors
18167  const unsigned nassociated_boundaries_and_regions =
18168  associated_boundaries_and_regions.size();
18169  if (nassociated_boundaries_and_regions > 0)
18170  {
18171  Flat_packed_unsigneds.push_back(1);
18172 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18173  Flat_packed_unsigneds_string.push_back(
18174  "The element is associated to boundaries and regions");
18175 #endif
18176 
18177  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
18178 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18179  std::stringstream junk;
18180  junk << "The element is associated to "
18181  << nassociated_boundaries_and_regions << " boundaries-regions";
18182  Flat_packed_unsigneds_string.push_back(junk.str());
18183 #endif
18184 
18185  // Package the ids of the associated boundaries, regions and the
18186  // corresponding face index for each boundary-region (if the
18187  // element is a corner element, it will have two faces
18188  // associated to the boundary-region)
18189  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
18190  {
18191  const unsigned b = associated_boundaries_and_regions[i][0];
18192  Flat_packed_unsigneds.push_back(b);
18193 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18194  std::stringstream junk;
18195  junk << "Element associated to boundary " << b << " of "
18196  << nassociated_boundaries_and_regions
18197  << " total associated boundaries-regions";
18198  Flat_packed_unsigneds_string.push_back(junk.str());
18199 #endif
18200 
18201  const unsigned r = associated_boundaries_and_regions[i][1];
18202  Flat_packed_unsigneds.push_back(r);
18203 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18204  std::stringstream junk2;
18205  junk2 << "Element associated to region " << r << " of "
18206  << nassociated_boundaries_and_regions
18207  << " total associated boundaries-regions";
18208  Flat_packed_unsigneds_string.push_back(junk2.str());
18209 #endif
18210 
18211  const unsigned f = face_index_on_boundary_and_region[i];
18212  Flat_packed_unsigneds.push_back(f);
18213 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18214  std::stringstream junk3;
18215  junk3 << "Face index " << f << " for associated boundary-region ("
18216  << b << "-" << r << ")";
18217  Flat_packed_unsigneds_string.push_back(junk3.str());
18218 #endif
18219  } // for (i < nassociated_boundaries_and_regions)
18220  } // if (nassociated_boundaries_and_regions > 0)
18221  else
18222  {
18223  Flat_packed_unsigneds.push_back(0);
18224 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18225  Flat_packed_unsigneds_string.push_back(
18226  "The element is NOT associated to boundaries and regions");
18227 #endif
18228  } // else if (nassociated_boundaries_and_regions > 0)
18229  }
18230  else
18231  {
18232  Flat_packed_unsigneds.push_back(0);
18233 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18234  Flat_packed_unsigneds_string.push_back(
18235  "The element is not associated to any original boundary");
18236 #endif
18237  }
18238 
18239  // ------------------------------------------------------------
18240  // Now review if the element is associated to a shared boundary
18241 
18242  // Store the shared boundaries, and therefore the face indexes
18243  // associated to the element
18244  Vector<unsigned> associated_shared_boundaries;
18245  Vector<unsigned> face_index_on_shared_boundary;
18246 
18247  // Get the shared boundaries in this processor
18248  Vector<unsigned> my_rank_shared_boundaries_ids;
18249  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18250 
18251  // Get the number of shared boundaries
18252  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18253  // Loop over the shared boundaries
18254  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18255  {
18256  // Get the boundary id
18257  const unsigned sb = my_rank_shared_boundaries_ids[i];
18258 
18259  // Get the number of elements associated to shared boundary sb
18260  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18261  for (unsigned e = 0; e < nboundary_ele; e++)
18262  {
18263  if (ele_pt == this->shared_boundary_element_pt(sb, e))
18264  {
18265  // Keep track of the boundaries associated to the element
18266  associated_shared_boundaries.push_back(sb);
18267  // Get the face index
18268  face_index_on_shared_boundary.push_back(
18269  this->face_index_at_shared_boundary(sb, e));
18270  }
18271  } // (e < nboundary_ele)
18272  } // (i < nmy_rank_shd_bnd)
18273 
18274  // If the element is associated to a shared boundary then package
18275  // all the relevant info
18276  const unsigned nassociated_shared_boundaries =
18277  associated_shared_boundaries.size();
18278  if (nassociated_shared_boundaries > 0)
18279  {
18280  Flat_packed_unsigneds.push_back(3);
18281 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18282  Flat_packed_unsigneds_string.push_back(
18283  "The element is a shared boundary element");
18284 #endif
18285  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18286 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18287  std::stringstream junk;
18288  junk << "The elements is associated to " << nassociated_shared_boundaries
18289  << "shared boundaries";
18290  Flat_packed_unsigneds_string.push_back(junk.str());
18291 #endif
18292 
18293  // Package the ids of the associated boundaries
18294  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18295  {
18296  const unsigned b = associated_shared_boundaries[i];
18297  Flat_packed_unsigneds.push_back(b);
18298 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18299  std::stringstream junk;
18300  junk << "Element associated to shared boundary " << b << " of "
18301  << nassociated_shared_boundaries << " total associated boundaries";
18302  Flat_packed_unsigneds_string.push_back(junk.str());
18303 #endif
18304 
18305  const unsigned f = face_index_on_shared_boundary[i];
18306  Flat_packed_unsigneds.push_back(f);
18307 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18308  std::stringstream junk2;
18309  junk2 << "Face index " << f << " for associated shared boundary " << b;
18310  Flat_packed_unsigneds_string.push_back(junk2.str());
18311 #endif
18312  }
18313  }
18314  else
18315  {
18316  Flat_packed_unsigneds.push_back(0);
18317 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18318  Flat_packed_unsigneds_string.push_back(
18319  "The element is not associated to any shared boundary");
18320 #endif
18321  }
18322  }
18323 
18324  //========start of get_required_nodal_information_helper==================
18325  /// Helper function to get the required nodal information from an
18326  /// haloed node so that a fully-functional halo node (and therefore element)
18327  /// can be created on the receiving process
18328  //========================================================================
18329  template<class ELEMENT>
18331  unsigned& iproc, Node* nod_pt)
18332  {
18333  unsigned my_rank = this->communicator_pt()->my_rank();
18334  const unsigned nproc = this->communicator_pt()->nproc();
18335 
18336  // Tell the halo copy of this node how many values there are
18337  // [NB this may be different for nodes within the same element, e.g.
18338  // when using Lagrange multipliers]
18339  unsigned n_val = nod_pt->nvalue();
18340  Flat_packed_unsigneds.push_back(n_val);
18341 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18342  Flat_packed_unsigneds_string.push_back("Number of values");
18343 #endif
18344 
18345  unsigned n_dim = nod_pt->ndim();
18346 
18347  // Default number of previous values to 1
18348  unsigned n_prev = 1;
18349  if (this->Time_stepper_pt != 0)
18350  {
18351  // Add number of history values to n_prev
18352  n_prev = this->Time_stepper_pt->ntstorage();
18353  }
18354 
18355  // -----------------------------------------------------
18356  // Is the node on an original boundary?
18357  // Store the original boundaries where the node may be
18358  Vector<unsigned> original_boundaries;
18359  // Loop over the original boundaries of the mesh and check if live
18360  // on one of them
18361  const unsigned n_bnd = this->initial_shared_boundary_id();
18362  for (unsigned bb = 0; bb < n_bnd; bb++)
18363  {
18364  // Which boundaries (could be more than one) is it on?
18365  if (nod_pt->is_on_boundary(bb))
18366  {
18367  original_boundaries.push_back(bb);
18368  }
18369  }
18370 
18371  const unsigned n_original_boundaries = original_boundaries.size();
18372  // Is the node on any original boundary?
18373  if (n_original_boundaries > 0)
18374  {
18375  // Indicate that the node is on an original boundary
18376  Flat_packed_unsigneds.push_back(2);
18377 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18378  Flat_packed_unsigneds_string.push_back(
18379  "Node is on the original boundaries");
18380 #endif
18381 
18382  Flat_packed_unsigneds.push_back(n_original_boundaries);
18383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18384  std::stringstream junk;
18385  junk << "Node is on " << n_original_boundaries << " original boundaries";
18386  Flat_packed_unsigneds_string.push_back(junk.str());
18387 #endif
18388 
18389  // Loop over the original boundaries the node is on
18390  for (unsigned i = 0; i < n_original_boundaries; i++)
18391  {
18392  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18393 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18394  std::stringstream junk;
18395  junk << "Node is on boundary " << original_boundaries[i] << " of "
18396  << nb;
18397  Flat_packed_unsigneds_string.push_back(junk.str());
18398 #endif
18399  // Get the boundary coordinate of the node
18400  Vector<double> zeta(1);
18401  nod_pt->get_coordinates_on_boundary(original_boundaries[i], zeta);
18402  Flat_packed_doubles.push_back(zeta[0]);
18403  }
18404  }
18405  else
18406  {
18407  // Indicate that the node is NOT on an original boundary
18408  Flat_packed_unsigneds.push_back(0);
18409 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18410  Flat_packed_unsigneds_string.push_back(
18411  "Node is on any original boundary");
18412 #endif
18413  }
18414 
18415  // -------------------------------------------------------
18416  // Is the node on shared boundaries?
18417  bool node_on_shared_boundary = false;
18418  // Loop over the shared boundaries with the iproc processors and
18419  // check if live on one of them
18420  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18421  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18422  {
18423  // Get the boundary id
18424  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18425  // Which boundaries (could be more than one) is it on?
18426  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18427  {
18428  node_on_shared_boundary = true;
18429  break;
18430  }
18431  }
18432 
18433  // If the node live on any of the shared boundaries with the iproc
18434  // processor then just get the node number according to the
18435  // sorted_shared_boundary_node_pt() scheme and send it accross
18436  if (node_on_shared_boundary)
18437  {
18438  Flat_packed_unsigneds.push_back(1);
18439 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18440  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18441 #endif
18442 
18443  // Store the shared boundaries where the node is on
18444  Vector<unsigned> shd_boundaries;
18445  // Loop over the shared boundaries with the iproc processor
18446  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18447  {
18448  // Get the boundary id
18449  const unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18450  // Which boundaries (could be more than one) is it on?
18451  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18452  {
18453  shd_boundaries.push_back(i_bnd);
18454  }
18455  }
18456 
18457  // Get the number of shared boundaries the node is on
18458  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18459  // Send the number of shared boundaries the node is on
18460  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18461 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18462  std::stringstream junk;
18463  junk << "Node is on " << n_shd_bnd_is_on << " shared boundaries";
18464  Flat_packed_unsigneds_string.push_back(junk.str());
18465 #endif
18466 
18467  // Loop over the shared boundaries to send their ids
18468  for (unsigned i = 0; i < n_shd_bnd_is_on; i++)
18469  {
18470  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18471 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18472  std::stringstream junk;
18473  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18474  Flat_packed_unsigneds_string.push_back(junk.str());
18475 #endif
18476  }
18477 
18478  // Given that the node is on at least one boundary get the index
18479  // of the node in one of the boundaries and send this index
18480  unsigned shared_boundary_id = shd_boundaries[0];
18481  // Get the number of nodes on the given shared boundary
18482  const unsigned n_nodes_on_shared_boundary =
18483  nsorted_shared_boundary_node(shared_boundary_id);
18484  // Store the index of the node on the shared boundary
18485  unsigned index_node_on_shared_boundary;
18486 #ifdef PARANOID
18487  // Flag to know if the node has been found
18488  bool found_index_node_on_shared_boundary = false;
18489 #endif
18490  // Loop over the nodes on the shared boundary to find the node
18491  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18492  {
18493  // Get the i-th node on the shared boundary
18494  Node* shared_node_pt =
18495  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18496  // Is the node we are looking for
18497  if (shared_node_pt == nod_pt)
18498  {
18499  // Store the index
18500  index_node_on_shared_boundary = i;
18501 #ifdef PARANOID
18502  // Mark as found
18503  found_index_node_on_shared_boundary = true;
18504 #endif
18505  break; // break
18506  }
18507 
18508  } // for (i < nnodes_on_shared_boundary)
18509 
18510 #ifdef PARANOID
18511  if (!found_index_node_on_shared_boundary)
18512  {
18513  std::ostringstream error_message;
18514  error_message << "The index of the node on boundary ("
18515  << shared_boundary_id << ") was not found.\n"
18516  << "The node coordinates are (" << nod_pt->x(0) << ","
18517  << nod_pt->x(1) << ").\n";
18518  throw OomphLibError(
18519  error_message.str(),
18520  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18521  OOMPH_EXCEPTION_LOCATION);
18522  }
18523 #endif
18524  // Send the index of the node on the shared boundary
18525  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18526 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18527  std::stringstream junk2;
18528  junk2 << "Node index on boundary " << boundaries[0] << " is "
18529  << index_node_on_shared_boundary;
18530  Flat_packed_unsigneds_string.push_back(junk2.str());
18531 #endif
18532 
18533  } // if (node_on_shared_boundary)
18534  else
18535  {
18536  // The node is not on a shared boundary
18537  Flat_packed_unsigneds.push_back(0);
18538 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18539  Flat_packed_unsigneds_string.push_back(
18540  "Node is not on a shared boundary");
18541 #endif
18542  }
18543 
18544  // ----------------------------------------------------------------
18545  // Is the node on any shared boundary where the receiver processor
18546  // is not involved?
18547 
18548  // Now check if the node is on a shared boundary created by the
18549  // current processor (my_rank) and other processor different that
18550  // the iproc processor. This info. will help to complete the sending
18551  // of halo(ed) information between processors
18552 
18553  // Flag to know if the node is on a shared boundary with other
18554  // processor
18555  bool node_on_shared_boundary_with_other_processors = false;
18556  // Count the number of other shared boundaries it could be on
18557  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18558 
18559  // Loop over the shared boundaries of the sent processor (my_rank)
18560  // and other processors (jproc)
18561  for (unsigned jproc = 0; jproc < nproc; jproc++)
18562  {
18563  // Do not search with the iproc processor , that was done before
18564  // above because we are sending info to that processor
18565  if (jproc != iproc)
18566  {
18567  // Get the number of shared boundaries with the jproc processor
18568  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
18569  // Loop over the shared boundaries
18570  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18571  {
18572  // Get the boundary id
18573  const unsigned j_shd_bnd =
18574  this->shared_boundaries_ids(my_rank, jproc, bb);
18575  // Is the node part of this boundary?
18576  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18577  {
18578  // DEBP("Sending to");
18579  // DEBP(iproc);
18580  // DEBP("Pair of procs where other shared");
18581  // DEBP(my_rank);
18582  // DEBP(jproc);
18583  // DEBP(i_bnd);
18584  node_on_shared_boundary_with_other_processors = true;
18585  // Increase the counter for the number of shared boundaries
18586  // with other processors the node is on
18587  nshared_boundaries_with_other_processors_have_node++;
18588  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18589 
18590  } // for (bb<n_jshd_bnd)
18591 
18592  } // if (jproc != iproc)
18593 
18594  } // for (jproc < nproc)
18595 
18596  // If the node is on a shared boundary with another processor
18597  // (my_rank, jproc), then send the flag and look for the info.
18598  if (node_on_shared_boundary_with_other_processors)
18599  {
18600  Flat_packed_unsigneds.push_back(4);
18601 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18602  Flat_packed_unsigneds_string.push_back(
18603  "Node is on shared boundary no related with the received processor: 4");
18604 #endif
18605 
18606  // The number of packages of information that will be sent to the
18607  // "iproc" processor. This helps to know how many packages of data
18608  // read from the received processor
18609  Flat_packed_unsigneds.push_back(
18610  nshared_boundaries_with_other_processors_have_node);
18611 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18612  std::stringstream junk;
18613  junk << "Number of other shared boundaries that the node is on: "
18614  << nshared_boundaries_with_other_processors_have_node;
18615  Flat_packed_unsigneds_string.push_back(junk.str());
18616 #endif
18617 
18618  // Counter to ensure that the correct number of data has been sent
18619  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18620  // Loop over the shared boundaries with other processors and get:
18621  // 1) The processors defining the shared boundary
18622  // 2) The shared boundary id
18623  // 3) The index of the node on the shared boundary
18624  Vector<unsigned> other_processor_1;
18625  Vector<unsigned> other_processor_2;
18626  Vector<unsigned> shd_bnd_ids;
18627  Vector<unsigned> indexes;
18628  // Loop over the processors again
18629  for (unsigned jproc = 0; jproc < nproc; jproc++)
18630  {
18631  // Do not search with the iproc processor, that was done before
18632  // above
18633  if (jproc != iproc)
18634  {
18635  // Get the number of shared boundaries with the jproc
18636  // processor
18637  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
18638  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18639  {
18640  // Get the boundary id
18641  const unsigned j_shd_bnd =
18642  this->shared_boundaries_ids(my_rank, jproc, bb);
18643  // Is the node part of this boundary?
18644  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18645  {
18646  // Include the first processor
18647  other_processor_1.push_back(my_rank);
18648  // Include the second processor
18649  other_processor_2.push_back(jproc);
18650  // Include the shared boundary id
18651  shd_bnd_ids.push_back(j_shd_bnd);
18652  // Increase the counter for found shared boundaries with
18653  // other processors
18654  counter_shd_bnd_with_other_procs_have_node++;
18655  }
18656 
18657  } // for (bb < nshared_bnd)
18658 
18659  } // if (jproc != iproc)
18660 
18661  } // for (jproc < nproc)
18662 
18663  // Get the indexes of the node on all the shared boundaries where
18664  // it was found
18665  const unsigned n_other_processors = other_processor_1.size();
18666  // Loop over the processors where the node was found
18667  for (unsigned i = 0; i < n_other_processors; i++)
18668  {
18669  // Get the shared boundary id
18670  unsigned shd_bnd_id = shd_bnd_ids[i];
18671  // Get the number of nodes on that shared boundary
18672  const unsigned n_nodes_on_shd_bnd =
18673  nsorted_shared_boundary_node(shd_bnd_id);
18674 
18675 #ifdef PARANOID
18676  bool found_index_node_on_shared_boundary = false;
18677 #endif
18678  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18679  {
18680  // Get the i-th shared boundary node
18681  Node* shared_node_pt = sorted_shared_boundary_node_pt(shd_bnd_id, i);
18682  // Is the same node?
18683  if (shared_node_pt == nod_pt)
18684  {
18685  // DEBP(i_node);
18686  // DEBP(nod_pt->x(0));
18687  // DEBP(nod_pt->x(1));
18688  // Include the index of the node
18689  indexes.push_back(i);
18690 #ifdef PARANOID
18691  // Mark as found the node
18692  found_index_node_on_shared_boundary = true;
18693 #endif
18694  break;
18695  } // if (shared_node_pt == nod_pt)
18696 
18697  } // for (i < n_nodes_on_shd_bnd)
18698 
18699 #ifdef PARANOID
18700  if (!found_index_node_on_shared_boundary)
18701  {
18702  std::ostringstream error_message;
18703  error_message << "The index of the node on boundary (" << shd_bnd_id
18704  << "), shared by other processors\nwas not found.\n"
18705  << "The node coordinates are (" << nod_pt->x(0) << ","
18706  << nod_pt->x(1) << ").\n";
18707  throw OomphLibError(
18708  error_message.str(),
18709  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18710  OOMPH_EXCEPTION_LOCATION);
18711  }
18712 #endif
18713  } // for (i < n_other_processors)
18714 
18715  // Now send the info. but first check that the number of found
18716  // nodes be the same that the previously found shared boundaries
18717  // with the node
18718 #ifdef PARANOID
18719  if (counter_shd_bnd_with_other_procs_have_node !=
18720  nshared_boundaries_with_other_processors_have_node)
18721  {
18722  std::ostringstream error_message;
18723  error_message << "The number of shared boundaries where the node is on "
18724  << "is different:\n"
18725  << "nshared_boundaries_with_other_processors_have_node: ("
18726  << nshared_boundaries_with_other_processors_have_node
18727  << ")\n"
18728  << "counter_shd_bnd_with_other_procs_have_node: ("
18729  << counter_shd_bnd_with_other_procs_have_node << ")\n";
18730  throw OomphLibError(
18731  error_message.str(),
18732  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18733  OOMPH_EXCEPTION_LOCATION);
18734  } // if (counter_shd_bnd_with_other_procs_have_node !=
18735  // nshared_boundaries_with_other_processors_have_node)
18736 #endif
18737 
18738  // Loop over the info. to send it
18739  for (unsigned i = 0; i < n_other_processors; i++)
18740  {
18741  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18742 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18743  std::stringstream junk1;
18744  junk1 << "Processor where the other shared boundary "
18745  << "has the node: " << other_processor_1[i];
18746  Flat_packed_unsigneds_string.push_back(junk1.str());
18747 #endif
18748 
18749  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18750 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18751  std::stringstream junk2;
18752  junk2 << "Processor where the other shared boundary "
18753  << "has the node: " << other_processor_2[i];
18754  Flat_packed_unsigneds_string.push_back(junk2.str());
18755 #endif
18756 
18757  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18758 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18759  std::stringstream junk3;
18760  junk3 << "Other shared boundary id where the node is on"
18761  << boundaries[i];
18762  Flat_packed_unsigneds_string.push_back(junk3.str());
18763 #endif
18764 
18765  Flat_packed_unsigneds.push_back(indexes[i]);
18766 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18767  std::stringstream junk4;
18768  junk4 << "Node index on other shared boundary " << boundaries[i]
18769  << " is " << indexes[i];
18770  Flat_packed_unsigneds_string.push_back(junk4.str());
18771 #endif
18772 
18773  } // for (i < n_other_processors)
18774 
18775  } // if (node_on_shared_boundary_with_other_processors)
18776  else
18777  {
18778  Flat_packed_unsigneds.push_back(0);
18779 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18780  Flat_packed_unsigneds_string.push_back(
18781  "Node is on any shared boundary with other processors");
18782 #endif
18783  } // else if (node_on_shared_boundary_with_other_processors)
18784 
18785  // Now check if it is required to send the info. of the node. If the
18786  // node is not on a shared boundary with the iproc processor then we
18787  // need to send the info.
18788 
18789  if (!node_on_shared_boundary)
18790  {
18791  // Send all the info. to create it
18792 
18793  // Is the Node algebraic? If so, send its ref values and
18794  // an indication of its geometric objects if they are stored
18795  // in the algebraic mesh
18796  AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
18797  if (alg_nod_pt != 0)
18798  {
18799  // The external mesh should be algebraic
18800  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
18801 
18802  // Get default node update function ID
18803  unsigned update_id = alg_nod_pt->node_update_fct_id();
18804  Flat_packed_unsigneds.push_back(update_id);
18805 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18806  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18807 #endif
18808 
18809  // Get reference values at default...
18810  unsigned n_ref_val = alg_nod_pt->nref_value();
18811  Flat_packed_unsigneds.push_back(n_ref_val);
18812 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18813  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18814 #endif
18815  for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
18816  {
18817  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18818  }
18819 
18820  // Access geometric objects at default...
18821  unsigned n_geom_obj = alg_nod_pt->ngeom_object();
18822  Flat_packed_unsigneds.push_back(n_geom_obj);
18823 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18824  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18825 #endif
18826  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
18827  {
18828  GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
18829 
18830  // Check this against the stored geometric objects in mesh
18831  unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
18832 
18833  // Default found index to zero
18834  unsigned found_geom_object = 0;
18835  for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
18836  {
18837  if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
18838  {
18839  found_geom_object = i_list;
18840  }
18841  }
18842  Flat_packed_unsigneds.push_back(found_geom_object);
18843 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18844  Flat_packed_unsigneds_string.push_back("Found geom object");
18845 #endif
18846  }
18847  } // (if alg_nod_pt!=0)
18848 
18849  // Is it a SolidNode?
18850  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
18851  if (solid_nod_pt != 0)
18852  {
18853  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
18854  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
18855  {
18856  for (unsigned t = 0; t < n_prev; t++)
18857  {
18858  Flat_packed_doubles.push_back(
18859  solid_nod_pt->variable_position_pt()->value(t, i_val));
18860  }
18861  }
18862 
18863  Vector<double> values_solid_node;
18864  solid_nod_pt->add_values_to_vector(values_solid_node);
18865  const unsigned nvalues_solid_node = values_solid_node.size();
18866  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18867 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18868  std::stringstream junk;
18869  junk << "Number of values solid node: " << nvalues_solid_node;
18870  Flat_packed_unsigneds_string.push_back(junk.str());
18871 #endif
18872  for (unsigned i = 0; i < nvalues_solid_node; i++)
18873  {
18874  Flat_packed_doubles.push_back(values_solid_node[i]);
18875  }
18876  }
18877 
18878  // Finally copy info required for all node types
18879  for (unsigned i_val = 0; i_val < n_val; i_val++)
18880  {
18881  for (unsigned t = 0; t < n_prev; t++)
18882  {
18883  Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
18884  }
18885  }
18886 
18887  // Now do positions
18888  for (unsigned idim = 0; idim < n_dim; idim++)
18889  {
18890  for (unsigned t = 0; t < n_prev; t++)
18891  {
18892  Flat_packed_doubles.push_back(nod_pt->x(t, idim));
18893  }
18894  }
18895 
18896  } // if (!node_on_shared_boundary)
18897  }
18898 
18899  //==========start of add_haloed_node_helper===============================
18900  /// Helper to add external haloed node that is not a master
18901  //========================================================================
18902  template<class ELEMENT>
18904  Node* nod_pt)
18905  {
18906  // Attempt to add this node as a haloed node
18907  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18908  const unsigned haloed_node_index =
18909  this->try_to_add_haloed_node_pt(iproc, nod_pt);
18910 
18911  // If it was added then the new index should match the size of the storage
18912  if (haloed_node_index == n_haloed_nod)
18913  {
18914  Flat_packed_unsigneds.push_back(1);
18915 
18916 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18917  std::stringstream junk;
18918  junk << "Node needs to be constructed [size="
18919  << Flat_packed_unsigneds.size() << "]; last entry: "
18920  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
18921  Flat_packed_unsigneds_string.push_back(junk.str());
18922 #endif
18923 
18924  // This helper function gets all the required information for the
18925  // specified node and stores it into MPI-sendable information
18926  // so that a halo copy can be made on the receiving process
18927  get_required_nodal_information_helper(iproc, nod_pt);
18928  }
18929  else // It was already added
18930  {
18931  Flat_packed_unsigneds.push_back(0);
18932 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18933  std::stringstream junk;
18934  junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
18935  << "]; last entry: "
18936  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
18937 
18938  Flat_packed_unsigneds_string.push_back(junk.str());
18939 #endif
18940 
18941  // This node is already a haloed node, so tell
18942  // the other process its index in the equivalent halo storage
18943  Flat_packed_unsigneds.push_back(haloed_node_index);
18944 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18945  Flat_packed_unsigneds_string.push_back("haloed node index");
18946 #endif
18947  }
18948  }
18949 
18950  //================= send_and_receive_haloed_info =======================
18951  /// Send the information of the elements that will be created on the other
18952  /// processor
18953  //======================================================================
18954  template<class ELEMENT>
18956  int& send_proc, int& recv_proc)
18957  {
18958  // Get the communicator of the mesh
18959  OomphCommunicator* comm_pt = this->communicator_pt();
18960 
18961  // Set MPI info
18962  MPI_Status status;
18963  MPI_Request request;
18964 
18965  // Prepare vectors to receive information
18966  Vector<double> received_double_values;
18967  Vector<unsigned> received_unsigned_values;
18968 
18969  // Send the double values associated with halo(ed) elements and nodes
18970  //-------------------------------------------------------------------
18971  unsigned send_count_double_values = Flat_packed_doubles.size();
18972  MPI_Isend(&send_count_double_values,
18973  1,
18974  MPI_UNSIGNED,
18975  send_proc,
18976  1,
18977  comm_pt->mpi_comm(),
18978  &request);
18979 
18980  int receive_count_double_values = 0;
18981  MPI_Recv(&receive_count_double_values,
18982  1,
18983  MPI_INT,
18984  recv_proc,
18985  1,
18986  comm_pt->mpi_comm(),
18987  &status);
18988  MPI_Wait(&request, MPI_STATUS_IGNORE);
18989 
18990  if (send_count_double_values != 0)
18991  {
18992  MPI_Isend(&Flat_packed_doubles[0],
18993  send_count_double_values,
18994  MPI_DOUBLE,
18995  send_proc,
18996  2,
18997  comm_pt->mpi_comm(),
18998  &request);
18999  }
19000  if (receive_count_double_values != 0)
19001  {
19002  received_double_values.resize(receive_count_double_values);
19003  MPI_Recv(&received_double_values[0],
19004  receive_count_double_values,
19005  MPI_DOUBLE,
19006  recv_proc,
19007  2,
19008  comm_pt->mpi_comm(),
19009  &status);
19010  }
19011  if (send_count_double_values != 0)
19012  {
19013  MPI_Wait(&request, MPI_STATUS_IGNORE);
19014  }
19015 
19016  // Now send unsigned values associated with halo(ed) elements and nodes
19017  //---------------------------------------------------------------------
19018  unsigned send_count_unsigned_values = Flat_packed_unsigneds.size();
19019 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19020  unsigned send_count_unsigned_string = Flat_packed_unsigneds_string.size();
19021 #ifdef PARANOID
19022  if (send_count_unsigned_string != send_count_unsigned_values)
19023  {
19024  std::ostringstream error_message;
19025  error_message << "The number of unsigned values to send to processor ("
19026  << send_proc
19027  << ") is different from the\nnumber of annotated strings "
19028  << "for the communication\n\n";
19029  throw OomphLibError(
19030  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
19031  }
19032 #endif // #ifdef PARANOID
19033 #endif
19034  MPI_Isend(&send_count_unsigned_values,
19035  1,
19036  MPI_UNSIGNED,
19037  send_proc,
19038  14,
19039  comm_pt->mpi_comm(),
19040  &request);
19041 
19042  int receive_count_unsigned_values = 0;
19043  MPI_Recv(&receive_count_unsigned_values,
19044  1,
19045  MPI_INT,
19046  recv_proc,
19047  14,
19048  comm_pt->mpi_comm(),
19049  &status);
19050 
19051  MPI_Wait(&request, MPI_STATUS_IGNORE);
19052 
19053  if (send_count_unsigned_values != 0)
19054  {
19055  MPI_Isend(&Flat_packed_unsigneds[0],
19056  send_count_unsigned_values,
19057  MPI_UNSIGNED,
19058  send_proc,
19059  15,
19060  comm_pt->mpi_comm(),
19061  &request);
19062 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19063  for (unsigned i = 0; i < send_count_unsigned_values; i++)
19064  {
19065  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc << " "
19066  << Flat_packed_unsigneds_string[i] << ": "
19067  << Flat_packed_unsigneds[i] << std::endl;
19068  }
19069 #endif
19070  }
19071  if (receive_count_unsigned_values != 0)
19072  {
19073  received_unsigned_values.resize(receive_count_unsigned_values);
19074  MPI_Recv(&received_unsigned_values[0],
19075  receive_count_unsigned_values,
19076  MPI_UNSIGNED,
19077  recv_proc,
19078  15,
19079  comm_pt->mpi_comm(),
19080  &status);
19081  }
19082 
19083  if (send_count_unsigned_values != 0)
19084  {
19085  MPI_Wait(&request, MPI_STATUS_IGNORE);
19086  }
19087 
19088  // Copy across into original containers -- these can now
19089  //------------------------------------------------------
19090  // be processed by create_external_halo_elements() to generate
19091  //------------------------------------------------------------
19092  // external halo elements
19093  //------------------------
19094  Flat_packed_doubles.resize(receive_count_double_values);
19095  for (int ii = 0; ii < receive_count_double_values; ii++)
19096  {
19097  Flat_packed_doubles[ii] = received_double_values[ii];
19098  }
19099  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
19100  for (int ii = 0; ii < receive_count_unsigned_values; ii++)
19101  {
19102  Flat_packed_unsigneds[ii] = received_unsigned_values[ii];
19103  }
19104  }
19105 
19106  //=====================================================================
19107  /// Creates (halo) element on the loop process based on the
19108  /// information received from each processor
19109  //=====================================================================
19110  template<class ELEMENT>
19112  unsigned& iproc,
19113  Vector<Node*>& new_nodes_on_domain,
19114  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19115  other_proc_shd_bnd_node_pt,
19116  Vector<Vector<Vector<unsigned>>>& global_node_names,
19117  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19118  Vector<Node*>& global_shared_node_pt)
19119  {
19120 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19121  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19122  << " Bool: New element needs to be constructed "
19123  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19124  << std::endl;
19125 #endif
19126 
19127  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19128  {
19129  // Create a new element from the communicated values
19130  // and coords from the process that located zeta
19131  GeneralisedElement* new_el_pt = new ELEMENT;
19132 
19133  // Add the element, it is a new element in the mesh
19134  this->add_element_pt(new_el_pt);
19135 
19136  // Add halo element to this mesh
19137  this->add_root_halo_element_pt(iproc, new_el_pt);
19138 
19139  // Cast to the FE pointer
19140  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(new_el_pt);
19141 
19142  // Check if new element is associated to any boundary
19143  this->add_halo_element_helper(iproc, f_el_pt);
19144 
19145  // Now we add nodes to the new element
19146  unsigned n_node = f_el_pt->nnode();
19147 
19148  for (unsigned j = 0; j < n_node; j++)
19149  {
19150  Node* new_nod_pt = 0;
19151 
19152  // Call the add halo node helper function
19153  add_halo_node_helper(new_nod_pt,
19154  new_nodes_on_domain,
19155  other_proc_shd_bnd_node_pt,
19156  iproc,
19157  j,
19158  f_el_pt,
19159  global_node_names,
19160  node_name_to_global_index,
19161  global_shared_node_pt);
19162 
19163  } // for (j<n_nod)
19164  }
19165  else // the element already exists as halo
19166  {
19167 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19168  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19169  << " Index of existing halo element "
19170  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19171  << std::endl;
19172 #endif
19173  // The index itself is in Flat_packed_unsigneds[...]
19174  unsigned halo_ele_index =
19175  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19176 
19177  // Use this index to get the element
19178  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(
19179  this->root_halo_element_pt(iproc, halo_ele_index));
19180 
19181  // If it's not a finite element die
19182  if (f_el_pt == 0)
19183  {
19184  throw OomphLibError("Halo element is not a FiniteElement\n",
19185  OOMPH_CURRENT_FUNCTION,
19186  OOMPH_EXCEPTION_LOCATION);
19187  }
19188 
19189  } // else the element already exists as halo
19190  }
19191 
19192  //========start of add_halo_element_helper==============================
19193  /// \short Helper function to create (halo) elements on the loop
19194  /// process based on the info received in send_and_received_located_info
19195  /// This function is in charge of verify if the element is associated to
19196  /// a boundary
19197  //======================================================================
19198  template<class ELEMENT>
19200  unsigned& iproc, FiniteElement* ele_pt)
19201  {
19202 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19203  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19204  << " Bool: Element is associated to an original boundary "
19205  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19206  << std::endl;
19207 #endif
19208 
19209  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19210  {
19211 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19212  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19213  << " How many boundaries are associated with the element "
19214  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19215  << std::endl;
19216 #endif
19217  const unsigned nassociated_boundaries =
19218  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19219 
19220  for (unsigned b = 0; b < nassociated_boundaries; b++)
19221  {
19222 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19223  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19224  << " Boundary associated to the element "
19225  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19226  << std::endl;
19227 #endif
19228  const unsigned bnd =
19229  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19230 
19231 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19232  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19233  << " Face index of the element "
19234  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19235  << std::endl;
19236 #endif
19237  const unsigned face_index =
19238  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19239 
19240  // Associate the element with the boundary and establish as many
19241  // face indexes it has
19242  this->Boundary_element_pt[bnd].push_back(ele_pt);
19243  this->Face_index_at_boundary[bnd].push_back(face_index);
19244 
19245  } // (b < nassociated_boundaries)
19246 
19247  // Here read the info. regarding the boundary-region of the element
19248 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19249  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19250  << " Bool: Element is associated to a boundary-region "
19251  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19252  << std::endl;
19253 #endif
19254 
19255  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19256  {
19257 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19258  oomph_info
19259  << "Rec:" << Counter_for_flat_packed_unsigneds
19260  << " How many boundaries-regions are associated with the element "
19261  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19262  << std::endl;
19263 #endif
19264  const unsigned nassociated_boundaries_and_regions =
19265  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19266 
19267  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19268  {
19269 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19270  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19271  << " Boundary associated to the element "
19272  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19273  << std::endl;
19274 #endif
19275  const unsigned bnd =
19276  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19277 
19278 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19279  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19280  << " Region associated to the element "
19281  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19282  << std::endl;
19283 #endif
19284  const unsigned region =
19285  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19286 
19287 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19288  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19289  << " Face index of the element in boundary-region "
19290  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19291  << std::endl;
19292 #endif
19293  const unsigned face_index =
19294  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19295 
19296  // Associate the element with the boundary-regions and establish
19297  // as many face indexes it has
19298  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19299  this->Face_index_region_at_boundary[bnd][region].push_back(
19300  face_index);
19301 
19302  } // for (br < nassociated_boundaries_and_regions)
19303 
19304  } // Is the element associated with a boundary-region?
19305  }
19306 
19307  // Now check if the element is associated to a shared boundary
19308 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19309  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19310  << " Bool: Element is associated to a shared boundary "
19311  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19312  << std::endl;
19313 #endif
19314  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 3)
19315  {
19316 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19317  oomph_info
19318  << "Rec:" << Counter_for_flat_packed_unsigneds
19319  << " How many shared boundaries are associated with the element "
19320  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19321  << std::endl;
19322 #endif
19323  const unsigned nassociated_shared_boundaries =
19324  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19325 
19326  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19327  {
19328 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19329  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19330  << " Shared boundary associated to the element "
19331  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19332  << std::endl;
19333 #endif
19334  const unsigned bnd =
19335  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19336 
19337 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19338  oomph_info
19339  << "Rec:" << Counter_for_flat_packed_unsigneds
19340  << " Face index of the element associated to the shared boundary "
19341  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19342  << std::endl;
19343 #endif
19344 
19345  const unsigned face_index =
19346  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19347 
19348  this->add_shared_boundary_element(bnd, ele_pt);
19349  this->add_face_index_at_shared_boundary(bnd, face_index);
19350 
19351  } // (b < nassociated_shared_boundaries)
19352 
19353  } // The element is associted with a shared boundary
19354  }
19355 
19356  //========start of add_halo_node_helper==========================
19357  /// Helper function to add halo node
19358  //===============================================================
19359  template<class ELEMENT>
19361  Node*& new_nod_pt,
19362  Vector<Node*>& new_nodes_on_domain,
19363  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19364  other_proc_shd_bnd_node_pt,
19365  unsigned& iproc,
19366  unsigned& node_index,
19367  FiniteElement* const& new_el_pt,
19368  Vector<Vector<Vector<unsigned>>>& global_node_names,
19369  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19370  Vector<Node*>& global_shared_node_pt)
19371  {
19372  // Given the node, received information about them from process
19373  // iproc, construct them on the current process
19374 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19375  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19376  << " Bool: New node needs to be constructed "
19377  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19378  << std::endl;
19379 #endif
19380  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19381  {
19382  // Construct a new node based upon sent information, or copy a node
19383  // from one of the shared boundaries
19384  construct_new_halo_node_helper(new_nod_pt,
19385  new_nodes_on_domain,
19386  other_proc_shd_bnd_node_pt,
19387  iproc,
19388  node_index,
19389  new_el_pt,
19390  global_node_names,
19391  node_name_to_global_index,
19392  global_shared_node_pt);
19393  }
19394  else
19395  {
19396 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19397  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19398  << " Index of existing halo node "
19399  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19400  << std::endl;
19401 #endif
19402 
19403  // Copy node from received location
19404  new_nod_pt = new_nodes_on_domain
19405  [Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
19406 
19407  new_el_pt->node_pt(node_index) = new_nod_pt;
19408  }
19409  }
19410 
19411  //========start of construct_new_halo_node_helper=================
19412  // Helper function which constructs a new external halo node (on new element)
19413  // with the required information sent from the haloed process
19414  //========================================================================
19415  template<class ELEMENT>
19417  Node*& new_nod_pt,
19418  Vector<Node*>& new_nodes_on_domain,
19419  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19420  other_proc_shd_bnd_node_pt,
19421  unsigned& iproc,
19422  unsigned& node_index,
19423  FiniteElement* const& new_el_pt,
19424  Vector<Vector<Vector<unsigned>>>& global_node_names,
19425  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19426  Vector<Node*>& global_shared_node_pt)
19427  {
19428  // The first entry indicates the number of values at this new Node
19429  //(which may be different across the same element e.g. Lagrange multipliers)
19430 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19431  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19432  << " Number of values of external halo node "
19433  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19434  << std::endl;
19435 #endif
19436  unsigned n_val = Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19437 
19438  // Null TimeStepper for now
19439  TimeStepper* time_stepper_pt = this->Time_stepper_pt;
19440  // Default number of previous values to 1
19441  unsigned n_prev = time_stepper_pt->ntstorage();
19442 
19443  // ------------------------------------------------------
19444  // Check if the node is on an original boundary
19445 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19446  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19447  << " Is the node on an original boundary "
19448  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19449  << std::endl;
19450 #endif
19451 
19452  // Flag to indicate if the node is on original boundaries
19453  const unsigned node_on_original_boundaries =
19454  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19455 
19456  // Store the original boundaries where the node is on
19457  Vector<unsigned> original_boundaries_node_is_on;
19458  // Store the zeta coordinates of the node on the original boundaries
19459  Vector<double> zeta_coordinates;
19460  // Store the number of original boundaries the node is on
19461  unsigned n_original_boundaries_node_is_on = 0;
19462 
19463  if (node_on_original_boundaries == 2)
19464  {
19465  // How many original boundaries does the node live on?
19466 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19467  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19468  << " Number of boundaries the node is on: "
19469  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19470  << std::endl;
19471 #endif
19472  n_original_boundaries_node_is_on =
19473  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19474 
19475  // Resize the containers
19476  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19477  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19478 
19479  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19480  {
19481  // Boundary number
19482 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19483  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19484  << " Node is on boundary "
19485  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19486  << std::endl;
19487 #endif
19488  original_boundaries_node_is_on[i] =
19489  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19490  zeta_coordinates[i] =
19491  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19492  }
19493 
19494  } // if (node_on_original_boundaries==2)
19495 #ifdef PARANOID
19496  else
19497  {
19498  if (node_on_original_boundaries != 0)
19499  {
19500  std::ostringstream error_message;
19501  error_message
19502  << "The current node is not on an original boundary, this should\n"
19503  << "be indicated by a zero flag. However, the read value for\n"
19504  << "that flag is (" << node_on_original_boundaries << ").\n\n";
19505  throw OomphLibError(
19506  error_message.str(),
19507  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19508  OOMPH_EXCEPTION_LOCATION);
19509  } // if (node_on_original_boundaries != 0)
19510  }
19511 #endif
19512 
19513  // --------------------------------------------------------------
19514  // Check if the node was on a shared boundary with the iproc
19515  // processor
19516 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19517  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19518  << " Is node on shared boundary? "
19519  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19520  << std::endl;
19521 #endif
19522  const unsigned is_node_on_shared_boundary =
19523  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19524  if (is_node_on_shared_boundary == 1)
19525  {
19526  // How many shared boundaries does the node live on?
19527 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19528  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19529  << " Number of boundaries the node is on: "
19530  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19531  << std::endl;
19532 #endif
19533  const unsigned n_shd_bnd_node_is_on =
19534  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19535  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19536  for (unsigned i = 0; i < n_shd_bnd_node_is_on; i++)
19537  {
19538  // Shared boundary number
19539 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19540  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19541  << " Node is on boundary "
19542  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19543  << std::endl;
19544 #endif
19545  shd_bnds_node_is_on[i] =
19546  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19547  }
19548 
19549  // Get the index of the node on the shared boundary
19550 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19551  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19552  << " Index of node on boundary "
19553  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19554  << std::endl;
19555 #endif
19556  // Get the node index of the node on the shared boundary
19557  unsigned node_index_on_shared_boundary =
19558  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19559 
19560  // Get the pointer to the node with the received info.
19561  new_nod_pt = this->sorted_shared_boundary_node_pt(
19562  shd_bnds_node_is_on[0], node_index_on_shared_boundary);
19563 
19564  } // if (is_node_on_shared_boundary == 1)
19565 #ifdef PARANOID
19566  else
19567  {
19568  if (is_node_on_shared_boundary != 0)
19569  {
19570  std::ostringstream error_message;
19571  error_message
19572  << "The current node is not on a shared boundary, this should\n"
19573  << "be indicated by a zero flag. However, the read value for\n"
19574  << "that flag is (" << is_node_on_shared_boundary << ").\n\n";
19575  throw OomphLibError(
19576  error_message.str(),
19577  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19578  OOMPH_EXCEPTION_LOCATION);
19579  } // if (node_on_shared_boundary != 0)
19580  }
19581 #endif
19582 
19583  // ------------------------------------------------------------
19584  // Is the node on a shared boundary with other processor?
19585 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19586  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19587  << " Is the node on shared boundaries with other processors "
19588  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19589  << std::endl;
19590 #endif
19591 
19592  // Is the node in shared boundaries no associated with the
19593  // receiver processor
19594  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19595  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19596 
19597  // The containers where to store the info.
19598  Vector<unsigned> other_processor_1;
19599  Vector<unsigned> other_processor_2;
19600  Vector<unsigned> other_shared_boundaries;
19601  Vector<unsigned> other_indexes;
19602 
19603  // How many shared bounaries with other processors the node lives on
19604  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19605 
19606  // Is the node on shared boundaries with other processors
19607  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19608  {
19609 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19610  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19611  << " In how many shared boundaries with other "
19612  << "processors is the node "
19613  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19614  << std::endl;
19615 #endif
19616 
19617  // How many nodes on other shared boundaries were found
19618  n_shd_bnd_with_other_procs_have_node =
19619  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19620 
19621  // Resize the containers
19622  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19623  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19624  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19625  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19626 
19627  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19628  {
19629 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19630  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19631  << " Processor where the other shared boundary"
19632  << "has the node"
19633  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19634  << std::endl;
19635 #endif
19636  // Read the other processor 1
19637  other_processor_1[i] =
19638  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19639 
19640 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19641  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19642  << " Processor where the other shared boundary"
19643  << "has the node"
19644  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19645  << std::endl;
19646 #endif
19647  // Read the other processor 2
19648  other_processor_2[i] =
19649  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19650 
19651 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19652  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19653  << " Other shared boundary id where the node is on: "
19654  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19655  << std::endl;
19656 #endif
19657 
19658  // Read the other shared boundary id
19659  other_shared_boundaries[i] =
19660  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19661 
19662 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19663  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19664  << " Node index on the other shared boundary "
19665  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19666  << std::endl;
19667 #endif
19668 
19669  // Read the node index on the other shared boundary
19670  other_indexes[i] =
19671  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19672 
19673  } // for (i < n_shd_bnd_with_other_procs_have_node)
19674 
19675  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19676 #ifdef PARANOID
19677  else
19678  {
19679  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19680  {
19681  std::ostringstream error_message;
19682  error_message
19683  << "The current node is not on a shared boundary with\n"
19684  << "other processors, this should be indicated by a zero flag.\n"
19685  << "However, the read value for that flag is ("
19686  << is_the_node_in_shared_boundaries_with_other_processors << ").\n\n";
19687  throw OomphLibError(
19688  error_message.str(),
19689  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19690  OOMPH_EXCEPTION_LOCATION);
19691  }
19692  }
19693 #endif
19694 
19695  // Now we have all the info. to decide whether the node should be
19696  // created or not
19697 
19698  // First check if the node is a shared boundary node
19699  if (is_node_on_shared_boundary == 1)
19700  {
19701  // We already have the node, we do not need to create it
19702 
19703  // Only check if we need to add boundary info. to the node
19704  if (node_on_original_boundaries == 2)
19705  {
19706  // The node is a boundary node, add the boundary info. before
19707  // adding it to the domain
19708 
19709  // Associate the node to the given boundaries
19710  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19711  {
19712  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19713  // Establish the boundary coordinates for the node
19714  Vector<double> zeta(1);
19715  zeta[0] = zeta_coordinates[i];
19716  new_nod_pt->set_coordinates_on_boundary(
19717  original_boundaries_node_is_on[i], zeta);
19718  }
19719 
19720  } // if (node_on_original_boundaries==2)
19721 
19722  // Add the node to the domain
19723  new_nodes_on_domain.push_back(new_nod_pt);
19724 
19725  // Add the node to the element
19726  new_el_pt->node_pt(node_index) = new_nod_pt;
19727 
19728  } // if (is_node_on_shared_boundary == 1)
19729 
19730  // Now check if the node is on a shared boundary with another
19731  // processor, if that is the case try to find the node that may have
19732  // been already sent by the other processors
19733 
19734  // This flags indicates if the node was found, and then decide if it
19735  // is required to create the node
19736  bool found_node_in_other_shared_boundaries = false;
19737  // Flag to indicate whether the node should be created as a boundary
19738  // node or not. If the node lies on a shared boundary with other
19739  // processor the we create it as a boundary node. The processor from
19740  // which we are receiving info. (iproc) may not know that the node
19741  // lies on an original boundary. If the node lies on an original
19742  // boundary then its info. will be sent by another processor, then
19743  // we can set its boundary info. since the node was constructed as a
19744  // boundary node
19745  bool build_node_as_boundary_node = false;
19746 
19747  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19748  {
19749  // Build the node as a boundary node
19750  build_node_as_boundary_node = true;
19751 
19752  // Try to get the node pointer in case that the node has been
19753  // already sent by the other processors
19754 
19755  // Get the number of initial shared boundaries to correct the
19756  // index of the shared boundary
19757  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19758 
19759  // Add the found nodes in the container
19760  Vector<Node*> found_node_pt;
19761 
19762  // Now try to find the node in any of the other shared boundaries
19763  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19764  {
19765  // We always check with the lower processor number. The
19766  // info. is only stored in one direction. More importantly,
19767  // this is done with the hope that the info. has been already
19768  // received from the other processor given that its info. was
19769  // processed before the current processor (iproc). NOTE that
19770  // it is not always the case that this info. has been received
19771  // from the other processors since it may have not require to
19772  // send the elements (and nodes) on the shared boundary with
19773  // the current processor (iproc).
19774  unsigned oproc1 = other_processor_1[i];
19775  unsigned oproc2 = other_processor_2[i];
19776  if (other_processor_1[i] > other_processor_2[i])
19777  {
19778  oproc1 = other_processor_2[i];
19779  oproc2 = other_processor_1[i];
19780  } // if (other_processor_1[i] > other_processor_2[i])
19781 
19782  // Re-compute the shared boundary id between the other
19783  // processors
19784  const unsigned shd_bnd_id =
19785  other_shared_boundaries[i] - initial_shd_bnd_id;
19786 
19787  // Read the index
19788  const unsigned index = other_indexes[i];
19789 
19790  // Check if there are nodes received from the other processor
19791  // and with the given shared boundary
19792  const unsigned n_nodes_on_other_processor =
19793  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19794 
19795  if (n_nodes_on_other_processor > 0)
19796  {
19797  // Check if we can find the index of the node in that
19798  // other processor and shared boundary id
19799  std::map<unsigned, Node*>::iterator it =
19800  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].find(index);
19801 
19802  // If the index exist then get the node pointer
19803  if (it !=
19804  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19805  {
19806  // Mark the node as found
19807  found_node_in_other_shared_boundaries = true;
19808  // Get the node pointer
19809  Node* tmp_node_pt = (*it).second;
19810 
19811  // Push back the node pointer
19812  found_node_pt.push_back(tmp_node_pt);
19813 
19814  } // if (it!=
19815  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19816 
19817  } // if (n_nodes_on_other_processor > 0)
19818 
19819  } // for (i < n_shd_bnd_with_other_procs_have_node)
19820 
19821  // If the node was found, then all their instances should be the
19822  // same but better check
19823  if (found_node_in_other_shared_boundaries)
19824  {
19825 #ifdef PARANOID
19826  const unsigned n_times_node_found = found_node_pt.size();
19827  for (unsigned j = 1; j < n_times_node_found; j++)
19828  {
19829  if (found_node_pt[j - 1] != found_node_pt[j])
19830  {
19831  std::ostringstream error_message;
19832  error_message
19833  << "The instances of the node that was found on\n"
19834  << "shared boundaries with other processors (but not\n"
19835  << "on shared boundaries with this processor) are not\n"
19836  << "the same.\n"
19837  << "These are the coordinates of the instances of the\n"
19838  << "nodes:\n"
19839  << "(" << found_node_pt[j - 1]->x(0) << ", "
19840  << found_node_pt[j - 1]->x(1) << ")\n"
19841  << "(" << found_node_pt[j]->x(0) << ", " << found_node_pt[j]->x(1)
19842  << ")\n"
19843  << "Dont be surprised if they are the same since the "
19844  << "node is\nrepeated.\n";
19845  throw OomphLibError(error_message.str(),
19846  OOMPH_CURRENT_FUNCTION,
19847  OOMPH_EXCEPTION_LOCATION);
19848 
19849  } // if (found_node_pt[j-1] != found_node_pt[j])
19850 
19851  } // for (j < ntimes_node_found)
19852 #endif // #ifdef PARANOID
19853 
19854  // Check if the node is a shared boundary node from the
19855  // current processor and the iproc processor, if that is the
19856  // case, and the node is also on a shared boundary with other
19857  // processor, then the pointer should be the same!!!
19858  if (is_node_on_shared_boundary == 1)
19859  {
19860  // const unsigned n_times_node_found = found_node_pt.size();
19861  // The pointer to the node is already assigned, it was
19862  // assigned when the node was found to be on a shared
19863  // boundary with the sending processor (iproc). Check that
19864  // any previous instances of the node have been copied
19865  // from the shared boundary, if that is not the case then
19866  // there is a problem
19867  if (found_node_pt[0] != new_nod_pt)
19868  {
19869  std::ostringstream error_message;
19870  error_message
19871  << "The pointer of the node that was found to be on a\n"
19872  << "shared boundary with other processor(s) and the pointer\n"
19873  << "of the node on shared boundary with the receiver\n"
19874  << "processor (iproc) are not the same. This means we have a\n"
19875  << "repeated node)\n"
19876  << "The coordinates for the nodes are:\n"
19877  << "(" << found_node_pt[0]->x(0) << ", " << found_node_pt[0]->x(1)
19878  << ")\n"
19879  << "(" << new_nod_pt->x(0) << ", " << new_nod_pt->x(1) << ")\n"
19880  << "Dont be surprised if they are the same since the "
19881  << "node is\nrepeated.\n";
19882  throw OomphLibError(error_message.str(),
19883  OOMPH_CURRENT_FUNCTION,
19884  OOMPH_EXCEPTION_LOCATION);
19885 
19886  } // if (found_node_pt[i] != new_nod_pt)
19887 
19888  } // if (is_node_on_shared_boundary == 1)
19889  else
19890  {
19891  // Take the first instance of the node in case that it was
19892  // found and is not on a shared boundary with the iproc
19893  // processor (the processor from which we are receiving
19894  // the info.)
19895  new_nod_pt = found_node_pt[0];
19896  }
19897 
19898  } // if (found_node_in_other_shared_boundaries)
19899 
19900  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19901 
19902  // -----------------------------------------------------------------
19903  // Create the node or read the received info if the node is not on a
19904  // shared boundary with the iproc processor
19905  if (is_node_on_shared_boundary != 1)
19906  {
19907  // If the node is on a shared boundary with other processor we
19908  // need to read all the info. since the processor that sent the
19909  // info. did not know that the node is part of another shared
19910  // boundary
19911 
19912  // If the node is not on a shared boundary (with any processor),
19913  // or if this is the first time that the info. of the node is
19914  // received from any of the processors with which it has a shared
19915  // boundary, then we create the node
19916 
19917  // Is the node a boundary node or should it be build as a boundary
19918  // node because it is on a shared boundary with other processors
19919  if (node_on_original_boundaries == 2 || build_node_as_boundary_node)
19920  {
19921  // Check if necessary to create the node, or if it has been
19922  // already found in shared boundaries with other processors
19923  if (!found_node_in_other_shared_boundaries)
19924  {
19925  // Construct a boundary node
19926  if (time_stepper_pt != 0)
19927  {
19928  new_nod_pt =
19929  new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
19930  }
19931  else
19932  {
19933  new_nod_pt = new_el_pt->construct_boundary_node(node_index);
19934  }
19935 
19936  } // if (!found_node_in_other_shared_boundaries)
19937  else
19938  {
19939  // If the node was found then assign the node to the element
19940  new_el_pt->node_pt(node_index) = new_nod_pt;
19941 
19942  } // else if (!found_node_in_other_shared_boundaries)
19943 
19944  // Associate the node to the given boundaries
19945  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19946  {
19947  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19948  // Establish the boundary coordinates for the node
19949  Vector<double> zeta(1);
19950  zeta[0] = zeta_coordinates[i];
19951  new_nod_pt->set_coordinates_on_boundary(
19952  original_boundaries_node_is_on[i], zeta);
19953  }
19954 
19955  } // if (node is on an original boundary)
19956  else
19957  {
19958  // Check if necessary to create the node, or if it has been
19959  // already found in shared boundaries with other processors
19960  if (!found_node_in_other_shared_boundaries)
19961  {
19962  // Construct an ordinary (non-boundary) node
19963  if (time_stepper_pt != 0)
19964  {
19965  new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
19966  }
19967  else
19968  {
19969  new_nod_pt = new_el_pt->construct_node(node_index);
19970  }
19971  } // if (!found_node_in_other_shared_boundaries)
19972  else
19973  {
19974  // If the node was found then assign the node to the element
19975  new_el_pt->node_pt(node_index) = new_nod_pt;
19976  } // else if (!found_node_in_other_shared_boundaries)
19977 
19978  } // else (the node is not a boundary node)
19979 
19980  // ... and gather all its information
19981 
19982  // If the node was found or not in other shared boundaries, this
19983  // is the first time the node is received from this processor
19984  // (iproc), therefore it is added to the vector of nodes received
19985  // from this processor (iproc)
19986  new_nodes_on_domain.push_back(new_nod_pt);
19987 
19988  // Check if necessary to state all the info. to the node if it has
19989  // been already found in shared boundaries with other processors
19990  if (!found_node_in_other_shared_boundaries)
19991  {
19992  // Add the node to the general node storage
19993  this->add_node_pt(new_nod_pt);
19994  } // if (!found_node_in_other_shared_boundaries)
19995 
19996  // Is the new constructed node Algebraic?
19997  AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
19998 
19999  // If it is algebraic, its node update functions will
20000  // not yet have been set up properly
20001  if (new_alg_nod_pt != 0)
20002  {
20003  // The AlgebraicMesh is the external mesh
20004  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
20005 
20006  /// The first entry of All_alg_nodal_info contains
20007  /// the default node update id
20008  /// e.g. for the quarter circle there are
20009  /// "Upper_left_box", "Lower right box" etc...
20010 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20011  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20012  << " Alg node update id "
20013  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20014  << std::endl;
20015 #endif
20016 
20017  unsigned update_id =
20018  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20019 
20020  Vector<double> ref_value;
20021 
20022  // The size of this vector is in the next entry
20023  // of All_alg_nodal_info
20024 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20025  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20026  << " Alg node # of ref values "
20027  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20028  << std::endl;
20029 #endif
20030  unsigned n_ref_val =
20031  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20032 
20033  // The reference values themselves are in
20034  // All_alg_ref_value
20035  ref_value.resize(n_ref_val);
20036  for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
20037  {
20038  ref_value[i_ref] =
20039  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20040  }
20041 
20042  Vector<GeomObject*> geom_object_pt;
20043  /// again we need the size of this vector as it varies
20044  /// between meshes; we also need some indication
20045  /// as to which geometric object should be used...
20046 
20047  // The size of this vector is in the next entry
20048  // of All_alg_nodal_info
20049 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20050  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20051  << " Alg node # of geom objects "
20052  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20053  << std::endl;
20054 #endif
20055  unsigned n_geom_obj =
20056  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20057 
20058  // The remaining indices are in the rest of
20059  // All_alg_nodal_info
20060  geom_object_pt.resize(n_geom_obj);
20061  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
20062  {
20063 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20064  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20065  << " Alg node: geom object index "
20066  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20067  << std::endl;
20068 #endif
20069  unsigned geom_index =
20070  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20071  // This index indicates which of the AlgebraicMesh's
20072  // stored geometric objects should be used
20073  // (0 is a null pointer; everything else should have
20074  // been filled in by the specific Mesh). If it
20075  // hasn't been filled in then the update_node_update
20076  // call should fix it
20077  geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
20078  }
20079 
20080  // Check if necessary to state all the info. to the node if it has
20081  // been already found in shared boundaries with other processors
20082  if (!found_node_in_other_shared_boundaries)
20083  {
20084  /// For the received update_id, ref_value, geom_object
20085  /// call add_node_update_info
20086  new_alg_nod_pt->add_node_update_info(
20087  update_id, alg_mesh_pt, geom_object_pt, ref_value);
20088 
20089  /// Now call update_node_update
20090  alg_mesh_pt->update_node_update(new_alg_nod_pt);
20091 
20092  } // if (!found_node_in_other_shared_boundaries)
20093 
20094  } // if (new_alg_nod_pt!=0)
20095 
20096  // Check if necessary to state all the info. to the node if it has
20097  // been already found in shared boundaries with other processors
20098  if (!found_node_in_other_shared_boundaries)
20099  {
20100  // Is the node a MacroElementNodeUpdateNode?
20101  MacroElementNodeUpdateNode* macro_nod_pt =
20102  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
20103 
20104  if (macro_nod_pt != 0)
20105  {
20106  // Need to call set_node_update_info; this requires
20107  // a Vector<GeomObject*> (taken from the mesh)
20108  Vector<GeomObject*> geom_object_vector_pt;
20109 
20110  // Access the required geom objects from the
20111  // MacroElementNodeUpdateMesh
20112  MacroElementNodeUpdateMesh* macro_mesh_pt =
20113  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
20114  geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
20115 
20116  // Get local coordinate of node in new element
20117  Vector<double> s_in_macro_node_update_element;
20118  new_el_pt->local_coordinate_of_node(node_index,
20119  s_in_macro_node_update_element);
20120 
20121  // Set node update info for this node
20122  macro_nod_pt->set_node_update_info(
20123  new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
20124  }
20125 
20126  } // if (!found_node_in_other_shared_boundaries)
20127 
20128  // If there are additional values, resize the node
20129  unsigned n_new_val = new_nod_pt->nvalue();
20130 
20131  // Check if necessary to state all the info. to the node if it has
20132  // been already found in shared boundaries with other processors
20133  if (!found_node_in_other_shared_boundaries)
20134  {
20135  if (n_val > n_new_val)
20136  {
20137  // If it has been necessary to resize then it may be becuse
20138  // the node is on a FSI boundary, if that is the case we need
20139  // to set a map for these external values
20140 
20141  // Cast to a boundary node
20142  BoundaryNodeBase* bnod_pt =
20143  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
20144 
20145  // Create storage, if it doesn't already exist, for the map
20146  // that will contain the position of the first entry of
20147  // this face element's additional values,
20148  if (bnod_pt->index_of_first_value_assigned_by_face_element_pt() == 0)
20149  {
20150  bnod_pt->index_of_first_value_assigned_by_face_element_pt() =
20151  new std::map<unsigned, unsigned>;
20152  }
20153 
20154  // Get pointer to the map
20155  std::map<unsigned, unsigned>* map_pt =
20156  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
20157 
20158  // The id of the face to which this node belong in the bulk
20159  // element
20160  const unsigned id_face = 0;
20161  // We only resize the node values Vector if we haven't done it yet
20162  std::map<unsigned, unsigned>::const_iterator p =
20163  map_pt->find(id_face);
20164 
20165  // If this node hasn't been resized for current id
20166  if (p == map_pt->end())
20167  {
20168  // assign the face element id and the position of the
20169  // first entry to the boundary node
20170  (*map_pt)[id_face] = n_new_val;
20171 
20172  // resize the node vector of values
20173  new_nod_pt->resize(n_val);
20174  }
20175 
20176  } // if (n_val>n_new_val)
20177 
20178  } // if (!found_node_in_other_shared_boundaries)
20179 
20180  // Is the new node a SolidNode?
20181  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
20182  if (solid_nod_pt != 0)
20183  {
20184  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
20185  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
20186  {
20187  for (unsigned t = 0; t < n_prev; t++)
20188  {
20189  double read_data =
20190  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20191 
20192  // Check if necessary to state all the info. to the node if it has
20193  // been already found in shared boundaries with other processors
20194  if (!found_node_in_other_shared_boundaries)
20195  {
20196  solid_nod_pt->variable_position_pt()->set_value(
20197  t, i_val, read_data);
20198  } // if (!found_node_in_other_shared_boundaries)
20199  }
20200  }
20201 
20202 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20203  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20204  << " Number of values solid node: "
20205  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20206  << std::endl;
20207 #endif
20208  const unsigned nvalues_solid_node =
20209  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20210  Vector<double> values_solid_node(nvalues_solid_node);
20211  for (unsigned i = 0; i < nvalues_solid_node; i++)
20212  {
20213  values_solid_node[i] =
20214  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20215  }
20216 
20217  // Check if necessary to state all the info. to the node if it has
20218  // been already found in shared boundaries with other processors
20219  if (!found_node_in_other_shared_boundaries)
20220  {
20221  unsigned index = 0;
20222  solid_nod_pt->read_values_from_vector(values_solid_node, index);
20223  }
20224  }
20225 
20226  // Get copied history values
20227  // unsigned n_val=new_nod_pt->nvalue();
20228  for (unsigned i_val = 0; i_val < n_val; i_val++)
20229  {
20230  for (unsigned t = 0; t < n_prev; t++)
20231  {
20232  double read_data =
20233  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20234 
20235  // Check if necessary to state all the info. to the node if it
20236  // has been already found in shared boundaries with other
20237  // processors
20238  if (!found_node_in_other_shared_boundaries)
20239  {
20240  new_nod_pt->set_value(t, i_val, read_data);
20241  } // if (!found_node_in_other_shared_boundaries)
20242  }
20243  }
20244 
20245  // Get copied history values for positions
20246  unsigned n_dim = new_nod_pt->ndim();
20247  for (unsigned idim = 0; idim < n_dim; idim++)
20248  {
20249  for (unsigned t = 0; t < n_prev; t++)
20250  {
20251  double read_data =
20252  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20253 
20254  // Check if necessary to state all the info. to the node if it
20255  // has been already found in shared boundaries with other
20256  // processors
20257  if (!found_node_in_other_shared_boundaries)
20258  {
20259  // Copy to coordinate
20260  new_nod_pt->x(t, idim) = read_data;
20261 
20262  } // if (!found_node_in_other_shared_boundaries)
20263  }
20264  }
20265 
20266  } // if (is_node_on_shared_boundary != 1)
20267 
20268  // If the node was not found in other shared boundaries (possibly
20269  // because it is the first time the node has been sent) then copy
20270  // the node to the shared boundaries where it should be, use the
20271  // special container for this cases
20272  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20273  // shared
20274  // boundaries with
20275  // other processors
20276  !found_node_in_other_shared_boundaries) // The node has not
20277  // been previously
20278  // set as
20279  // shared with
20280  // other processors
20281  // (first time)
20282  {
20283  // Update the node pointer in all the (references) of the node
20284  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20285  other_proc_shd_bnd_node_pt,
20286  other_processor_1,
20287  other_processor_2,
20288  other_shared_boundaries,
20289  other_indexes,
20290  global_node_names,
20291  node_name_to_global_index,
20292  global_shared_node_pt);
20293 
20294  } // if (!found_node_in_other_shared_boundaries)
20295  }
20296 
20297  //========start of update_other_proc_shd_bnd_node_helper=================
20298  // Helper function that assigns/updates the references to the node so
20299  // that it can be found with any other reference
20300  //========================================================================
20301  template<class ELEMENT>
20303  Node*& new_node_pt,
20304  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
20305  other_proc_shd_bnd_node_pt,
20306  Vector<unsigned>& other_processor_1,
20307  Vector<unsigned>& other_processor_2,
20308  Vector<unsigned>& other_shared_boundaries,
20309  Vector<unsigned>& other_indexes,
20310  Vector<Vector<Vector<unsigned>>>& global_node_names,
20311  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
20312  Vector<Node*>& global_shared_node_pt)
20313  {
20314  // Get the number of initial shared boundaries to correct the index
20315  // of the shared boundary
20316  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20317 
20318 #ifdef PARANOID
20319  // Get the number of instances of the node on other shared
20320  // boundaries with other processors
20321  const unsigned n_data = other_processor_1.size();
20322 #endif // #ifdef PARANOID
20323 
20324  // Create the first node name
20325  Vector<unsigned> node_name(4);
20326  node_name[0] = other_processor_1[0];
20327  node_name[1] = other_processor_2[0];
20328  node_name[2] = other_shared_boundaries[0];
20329  node_name[3] = other_indexes[0];
20330 
20331 #ifdef PARANOID
20332  // Get the global node index, and all the names of the node
20333  std::map<Vector<unsigned>, unsigned>::iterator it =
20334  node_name_to_global_index.find(node_name);
20335  if (it == node_name_to_global_index.end())
20336  {
20337  std::ostringstream error_stream;
20338  error_stream << "The node name does not exist in the global node names\n"
20339  << "This is the name of the node\n"
20340  << "Name: iproc, jproc, ishd_bnd, idx\n"
20341  << "Name: " << node_name[0] << ", " << node_name[1] << ", "
20342  << node_name[2] << ", " << node_name[3] << "\n";
20343  throw OomphLibError(
20344  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20345  } // if (it!=node_name_to_global_index.end())
20346 #endif // #ifdef PARANOID
20347 
20348  // Get the global node index
20349  const unsigned iglobal_node = node_name_to_global_index[node_name];
20350  // Add the node to the global shared node container
20351  global_shared_node_pt[iglobal_node] = new_node_pt;
20352  // Get the names
20353  Vector<Vector<unsigned>> inode_names = global_node_names[iglobal_node];
20354  // Get the number of names of the node
20355  const unsigned n_names = inode_names.size();
20356 
20357 #ifdef PARANOID
20358  // Check that the received names of the node are part of the global
20359  // node names
20360  unsigned n_found_node_names_on_global_node_name = 0;
20361  // loop over the input node names
20362  for (unsigned j = 0; j < n_data; j++)
20363  {
20364  // loop over the inode_names
20365  for (unsigned k = 0; k < n_names; k++)
20366  {
20367  // Is this input name part of the global node names?
20368  if (inode_names[k][0] == other_processor_1[j] &&
20369  inode_names[k][1] == other_processor_2[j] &&
20370  inode_names[k][2] == other_shared_boundaries[j] &&
20371  inode_names[k][3] == other_indexes[j])
20372  {
20373  // Increase the number of found input node names in the
20374  // global node names
20375  n_found_node_names_on_global_node_name++;
20376  }
20377 
20378  } // for (k < n_names)
20379 
20380  } // for (j < n_data)
20381 
20382  // Were all the input node names found on the global node names?
20383  if (n_found_node_names_on_global_node_name != n_data)
20384  {
20385  std::ostringstream error_stream;
20386  error_stream
20387  << "Not all the node names of the current node were found on the\n"
20388  << "global node names. This happened when adding the node pointer\n"
20389  << "to the data structure that keeps tracks of nodes on shared\n"
20390  << "boundaries with other processors\n\n"
20391  << "These are the names of the current node\n"
20392  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20393  for (unsigned j = 0; j < n_data; j++)
20394  {
20395  error_stream << "Name(" << j << "): " << other_processor_1[j] << ", "
20396  << other_processor_2[j] << ", "
20397  << other_shared_boundaries[j] << ", " << other_indexes[j]
20398  << "\n";
20399  }
20400 
20401  error_stream << "\n\nThese are the names of the global node\n"
20402  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20403  for (unsigned k = 0; k < n_names; k++)
20404  {
20405  error_stream << "Name(" << k << "): " << inode_names[k][0] << ", "
20406  << inode_names[k][1] << ", " << inode_names[k][2] << ", "
20407  << inode_names[k][3] << "\n";
20408  }
20409 
20410  throw OomphLibError(
20411  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20412  }
20413 #endif // #ifdef PARANOID
20414 
20415  // Set the node pointer in all of its names
20416  for (unsigned j = 0; j < n_names; j++)
20417  {
20418  // Get the j-th node name
20419  const unsigned iproc = inode_names[j][0];
20420  const unsigned jproc = inode_names[j][1];
20421  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20422  const unsigned index = inode_names[j][3];
20423 
20424  // The info. is stored only in one direction
20425  // Get the smallest processor number
20426  if (iproc < jproc)
20427  {
20428  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index] = new_node_pt;
20429  }
20430  else
20431  {
20432  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index] = new_node_pt;
20433  }
20434 
20435  } // for (j < n_names)
20436  }
20437 
20438  // *********************************************************************
20439  // End communication functions
20440  // *********************************************************************
20441 
20442  // *********************************************************************
20443  // BEGIN: Methods to perform load balance
20444  // *********************************************************************
20445 
20446  //======================================================================
20447  /// \short Performs the load balancing for unstructured meshes, the
20448  /// load balancing strategy is based on mesh migration
20449  //======================================================================
20450  template<class ELEMENT>
20452  const Vector<unsigned>& target_domain_for_local_non_halo_element)
20453  {
20454  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20455 
20456  // This method can only be called when the mesh has been already
20457  // distributed
20458  if (!this->is_mesh_distributed())
20459  {
20460  std::ostringstream warning_message;
20461  warning_message
20462  << "\n===============================================================\n"
20463  << "The load balancing can only be performed in distributed meshes,\n"
20464  << "your mesh has not been distributed.\n"
20465  << "==============================================================="
20466  "\n\n";
20467  OomphLibWarning(warning_message.str(),
20468  OOMPH_CURRENT_FUNCTION,
20469  OOMPH_EXCEPTION_LOCATION);
20470  // Return
20471  return;
20472  }
20473 
20474  // Get the number of processors
20475  const unsigned nproc = this->communicator_pt()->nproc();
20476  // Get the rank of the current processors
20477  const unsigned my_rank = this->communicator_pt()->my_rank();
20478 
20479  // Check that there are at least two processors
20480  if (nproc == 1)
20481  {
20482  std::ostringstream warning_message;
20483  warning_message
20484  << "\n===============================================================\n"
20485  << "The load balancing can only be performed when there are at least\n"
20486  << "two procesors, the current number of processors is one.\n"
20487  << "==============================================================="
20488  "\n\n";
20489  OomphLibWarning(warning_message.str(),
20490  OOMPH_CURRENT_FUNCTION,
20491  OOMPH_EXCEPTION_LOCATION);
20492  // Return
20493  return;
20494  }
20495 
20496  // Get the time before load balance
20497  double t_start_overall_load_balance = 0.0;
20498  if (Print_timings_level_load_balance > 1)
20499  {
20500  t_start_overall_load_balance = TimingHelpers::timer();
20501  }
20502 
20503  // Get the number of elements in the mesh before load balance
20504  const unsigned nelement_before_load_balance = this->nelement();
20505 
20506 #ifdef PARANOID
20507  // The number of elements in the mesh and the number of target
20508  // domains for the local non halo elements in the mesh should match
20509  if (nnon_halo_element() != target_domain_for_local_non_halo_element.size())
20510  {
20511  std::ostringstream error_message;
20512  error_message << "The number of non halo elements in the current mesh ("
20513  << nnon_halo_element() << ") and the number\n"
20514  << "of target areas for the local non halo elements ("
20515  << target_domain_for_local_non_halo_element.size()
20516  << ") is different\n\n";
20517  throw OomphLibError(
20518  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20519  }
20520 #endif
20521 
20522  // Backup pointers to elements in this mesh
20523  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20524  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20525  {
20526  backed_up_ele_pt[e] = this->finite_element_pt(e);
20527  }
20528 
20529  // =====================================================================
20530  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20531  // =====================================================================
20532 
20533  // Get the time to get the domains of halo elements
20534  double tt_start_get_domains_halo_elements = 0.0;
20535  if (Print_timings_level_load_balance > 1)
20536  {
20537  tt_start_get_domains_halo_elements = TimingHelpers::timer();
20538  }
20539 
20540  // Get the new domains for the halo elements
20541 
20542  // Send the new domains for the current haloed elements, and receive
20543  // the new domains for the current halo elements
20544  // -- 1) On the current processor get the new domains for the
20545  // haloed elements
20546  // -- 2) Then send this info. to all the processor that have a
20547  // halo copy of the element
20548 
20549  // The storing for the new domains of the haloed elements (sent to
20550  // other processors)
20551  Vector<Vector<unsigned>> new_domains_haloed_elements(nproc);
20552  // The storing for the new domains of the halo elements (received
20553  // from other processors)
20554  Vector<Vector<unsigned>> new_domains_halo_elements(nproc);
20555 
20556  // First resize the containers by getting the current number of
20557  // halo/haloed elements within each processor
20558  for (unsigned iproc = 0; iproc < nproc; iproc++)
20559  {
20560  // There are no halo/haloed elements with myself (my_rank
20561  // processor)
20562  if (iproc != my_rank)
20563  {
20564  // Get the number of halo elements with iproc processor
20565  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20566  // Resize the container
20567  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20568 
20569  // Get the number of haloed elements with iproc processor
20570  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20571  // Resize the container
20572  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20573  } // if (iproc != my_rank)
20574  } // for (iproc < nproc)
20575 
20576 #ifdef PARANOID
20577  // Count the number of found haloed elements
20578  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20579 #endif
20580 
20581  // Go through all the haloed elements and find their new domain
20582 
20583  // Get the haloed elements with in each processor and check if the
20584  // element is haloed with the processor
20585  for (unsigned iproc = 0; iproc < nproc; iproc++)
20586  {
20587  // There are no halo/haloed elements with myself (my_rank
20588  // processor)
20589  if (iproc != my_rank)
20590  {
20591  // Get the number of haloed elements with iproc processor
20592  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20593 
20594  // Loop over the haloed elements
20595  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20596  {
20597  // Get the ihd-th haloed element with "iproc" processor
20598  GeneralisedElement* haloed_ele_pt =
20599  this->root_haloed_element_pt(iproc, ihd);
20600 
20601  // The counter for the nonhalo elements
20602  unsigned nh_count4 = 0;
20603  // Find the element in the general elements container
20604  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20605  {
20606  // Get the e-th element
20607  GeneralisedElement* ele_pt = this->element_pt(e);
20608  // Check if the element is a nonhalo element
20609  if (!ele_pt->is_halo())
20610  {
20611  // Increase the counter for nonhalo elements, in case the
20612  // haloed element is found get the (nh_count4-1) position
20613  // in the target domains vector
20614  nh_count4++;
20615 
20616  if (ele_pt == haloed_ele_pt)
20617  {
20618  // Get the new domain for this element
20619  const unsigned element_domain =
20620  target_domain_for_local_non_halo_element[nh_count4 - 1];
20621  // Here decrease the counter ---------------------^
20622 
20623  // Set the new domain for the haloed element in the
20624  // special container
20625  new_domains_haloed_elements[iproc][ihd] = element_domain;
20626 #ifdef PARANOID
20627  // Increase the counter
20628  counter_for_found_haloed_elements[iproc]++;
20629 #endif
20630  // ... and break the "for" with the general
20631  // elements. Continue with the next haloed element
20632  break;
20633 
20634  } // if (ele_pt == haloed_ele_pt))
20635 
20636  } // if (!ele_pt->is_halo())
20637 
20638  } // for (e < nelement_before_load_balance)
20639 
20640  } // for (ihd < n_haloed_iproc)
20641 
20642  } // if (iproc != my_rank)
20643 
20644  } // for (iproc < nproc)
20645 
20646 #ifdef PARANOID
20647  // Check that all the haloed elements with all processors have been
20648  // found
20649  for (unsigned iproc = 0; iproc < nproc; iproc++)
20650  {
20651  // There are no halo/haloed elements with myself (my_rank
20652  // processor)
20653  if (iproc != my_rank)
20654  {
20655  // Get the number of haloed elements with "iproc" processor
20656  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20657 
20658  // Compare the number of found haloed elements with the current
20659  // number of haloed elements
20660  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20661  {
20662  std::ostringstream error_message;
20663  error_message << "The independent counting of found haloed elements ("
20664  << counter_for_found_haloed_elements[iproc]
20665  << ") with processor (" << iproc
20666  << ") is not equal to the number of haloed elements ("
20667  << n_haloed_iproc << ") with processor (" << iproc
20668  << ")\n";
20669  throw OomphLibError(error_message.str(),
20670  OOMPH_CURRENT_FUNCTION,
20671  OOMPH_EXCEPTION_LOCATION);
20672  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20673 
20674  } // if (iproc != my_rank)
20675 
20676  } // for (iproc < nproc)
20677 #endif
20678 
20679  // Now we have the new domains for the haloed elements
20680 
20681  // Send this info. to the processor with a halo copy of the haloed
20682  // elements and set the new domains in the halo copies
20683 
20684  // First put all the info. in a flat package array
20685  Vector<unsigned> new_domains_haloed_flat_unsigned;
20686  // Put in a vector the number of haloed elements within each
20687  // processor
20688  Vector<int> nhaloed_elements_with_iproc(nproc);
20689  for (unsigned iproc = 0; iproc < nproc; iproc++)
20690  {
20691  // There are no halo/haloed elements with myself (my_rank
20692  // processor)
20693  if (iproc != my_rank)
20694  {
20695  // Get the number of haloed elements with "iproc" processor
20696  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20697  // Copy the number of haloed elements with "iproc" processor
20698  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20699  // Copy the new domains of the haloed elements in the flat
20700  // package
20701  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20702  {
20703  new_domains_haloed_flat_unsigned.push_back(
20704  new_domains_haloed_elements[iproc][i]);
20705  } // for (i < n_haloed_ele_iproc)
20706 
20707  } // if (iproc != my_rank)
20708 
20709  } // for (iproc < nproc)
20710 
20711  // The offsets of the flat package within each processor
20712  Vector<int> offset_haloed_elements_with_iproc(nproc);
20713  offset_haloed_elements_with_iproc[0] = 0;
20714  for (unsigned ip = 1; ip < nproc; ip++)
20715  {
20716  // Compute the offset to send the values to each processor
20717  offset_haloed_elements_with_iproc[ip] =
20718  offset_haloed_elements_with_iproc[ip - 1] +
20719  nhaloed_elements_with_iproc[ip - 1];
20720  } // for (ip < nproc)
20721 
20722  // Prepare to receive the data
20723 
20724  // Compute the number of data (halo elements) to receive from each
20725  // processor and the displacements within each processor
20726 
20727  // Counter for the total number of halo elements within all processors
20728  unsigned counter_halo_ele_with_all_procs = 0;
20729 
20730  // Put in a vector the number of halo elements expected to receive
20731  // from each processor
20732  Vector<int> nhalo_elements_with_iproc(nproc);
20733  // Compute the number of total halo elements of (my_rank) this
20734  // processor with all other processors
20735  for (unsigned iproc = 0; iproc < nproc; iproc++)
20736  {
20737  // There are no halo/haloed elements with myself (my_rank
20738  // processor)
20739  if (iproc != my_rank)
20740  {
20741  // Get the number of halo elements with "iproc" processor
20742  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20743  // Copy the number of halo elements with "iproc" processor
20744  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20745  // Add the number of elements with this processor
20746  counter_halo_ele_with_all_procs += n_halo_ele_iproc;
20747  } // if (iproc != my_rank)
20748 
20749  } // for (iproc < nproc)
20750 
20751  // The offsets of the flat package within each processor
20752  Vector<int> offset_halo_elements_with_iproc(nproc);
20753  offset_halo_elements_with_iproc[0] = 0;
20754  for (unsigned ip = 1; ip < nproc; ip++)
20755  {
20756  // Compute the offset to receive the values from each processor
20757  offset_halo_elements_with_iproc[ip] =
20758  offset_halo_elements_with_iproc[ip - 1] +
20759  nhalo_elements_with_iproc[ip - 1];
20760  } // for (ip < nproc)
20761 
20762  // The flat container to receive the new domains of the halo
20763  // elements in the current processor
20764 
20765  // The flat package where all the info. will be gather from the
20766  // other processors (the halo flat package)
20767  Vector<unsigned> new_domains_halo_flat_unsigned(
20768  counter_halo_ele_with_all_procs);
20769 
20770  // Perform the sending and receiving of information to and from all
20771  // processors
20772  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20773  &nhaloed_elements_with_iproc[0], // int *sendcnts
20774  &offset_haloed_elements_with_iproc[0], // int *sdispls
20775  MPI_UNSIGNED, // MPI_Datatype sendtype
20776  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20777  &nhalo_elements_with_iproc[0], // int *recvcnts
20778  &offset_halo_elements_with_iproc[0], // int *rdispls
20779  MPI_UNSIGNED, // MPI_Datatype recvtype
20780  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20781 
20782  // Once received the new domains for the halo elements, copy the
20783  // domains back to an easier to handle container (from the flat
20784  // package to the one with the different halo elements domains
20785  // within each processor)
20786  unsigned counter_new_domains_halo_ele = 0;
20787  for (unsigned iproc = 0; iproc < nproc; iproc++)
20788  {
20789  // There are no halo/haloed elements with myself (my_rank
20790  // processor)
20791  if (iproc != my_rank)
20792  {
20793  // Get the number of halo elements with "iproc"
20794  const unsigned ntmp_halo_elements_with_iproc =
20795  nhalo_elements_with_iproc[iproc];
20796  // Loop over the number of halo elements within "iproc" and copy
20797  // the elements from the flat package
20798  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20799  {
20800  // Copy the new domain of the halo elements from the flat
20801  // package to an easier to use container
20802  new_domains_halo_elements[iproc][i] =
20803  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20804  }
20805  } // if (iproc != my_rank)
20806  } // for (iproc < nproc)
20807 
20808  // The time to get domains of halo elements
20809  if (Print_timings_level_load_balance > 1)
20810  {
20811  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20812  << TimingHelpers::timer() - tt_start_get_domains_halo_elements
20813  << std::endl;
20814  }
20815 
20816  // =====================================================================
20817  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20818  // =====================================================================
20819 
20820  // =====================================================================
20821  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20822  // ELEMENTS
20823  // =====================================================================
20824 
20825  // Get the time to get FiniteElement versions from Generalised
20826  // halo(ed) elements
20827  double tt_start_get_fe_version_from_ge_halo_ed = 0.0;
20828  if (Print_timings_level_load_balance > 1)
20829  {
20830  tt_start_get_fe_version_from_ge_halo_ed = TimingHelpers::timer();
20831  }
20832 
20833  // The finite element storage for the halo elements
20834  Vector<Vector<FiniteElement*>> f_halo_element_pt(nproc);
20835  // The finite element storage for the haloed elements
20836  Vector<Vector<FiniteElement*>> f_haloed_element_pt(nproc);
20837  // Loop over the processors
20838  for (unsigned iproc = 0; iproc < nproc; iproc++)
20839  {
20840  // There are no halo(ed) elements with myself
20841  if (iproc != my_rank)
20842  {
20843  // Get the number of halo elements with the "iproc" processor
20844  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20845  // Get the halo elements with the "iproc" processor
20846  Vector<GeneralisedElement*> halo_element_pt_iproc =
20847  this->root_halo_element_pt(iproc);
20848  // Resize the finite element container
20849  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20850  // Loop over the halo elements
20851  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20852  {
20853  // Get the finite element
20854  FiniteElement* ele_pt =
20855  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20856  // Store the finite element version of the element
20857  f_halo_element_pt[iproc][ih] = ele_pt;
20858  } // for (ih < nhalo_ele_iproc)
20859 
20860  // Get the number of haloed elements with the "iproc" processor
20861  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20862  // Get the haloed elements with the "iproc" processor
20863  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20864  this->root_haloed_element_pt(iproc);
20865  // Resize the finite element container
20866  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20867  // Loop over the haloed elements
20868  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20869  {
20870  // Get the finite element
20871  FiniteElement* ele_pt =
20872  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20873  // Store the finite element version of the element
20874  f_haloed_element_pt[iproc][ihd] = ele_pt;
20875  } // for (ih < nhaloed_ele_iproc)
20876 
20877  } // if (iproc != my_rank)
20878 
20879  } // for (iproc < nproc)
20880 
20881  // The time to get FiniteElement versions from Generalised halo(ed)
20882  // elements
20883  if (Print_timings_level_load_balance > 1)
20884  {
20885  oomph_info << "CPU for getting finite element versions from generalised "
20886  "halo(ed) elements (load balance) [2]: "
20887  << TimingHelpers::timer() -
20888  tt_start_get_fe_version_from_ge_halo_ed
20889  << std::endl;
20890  }
20891 
20892  // =====================================================================
20893  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20894  // ELEMENTS
20895  // =====================================================================
20896 
20897  // =====================================================================
20898  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20899  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20900  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20901  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20902  // =====================================================================
20903 
20904  // Get the time to prepare elements to send to other processors
20905  double tt_start_prepare_element_to_send = 0.0;
20906  if (Print_timings_level_load_balance > 1)
20907  {
20908  tt_start_prepare_element_to_send = TimingHelpers::timer();
20909  }
20910 
20911  // Store the elements that will be sent to other processors
20912  Vector<Vector<FiniteElement*>> elements_to_send_pt(nproc);
20913 
20914  // Associate the nodes of each element with the processor the
20915  // element will live on
20916  std::map<Data*, std::set<unsigned>>
20917  processors_associated_with_data_before_load_balance;
20918 
20919  // Compute the elements that will be sent to other processor and
20920  // associate the nodes with the processor the element will live on
20921  unsigned nh_count3 = 0;
20922  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20923  {
20924  // Get the element
20925  FiniteElement* ele_pt = this->finite_element_pt(e);
20926  // Only work with nonhalo elements
20927  if (!(ele_pt->is_halo()))
20928  {
20929  // Get the new domain for the elment
20930  const unsigned element_domain =
20931  target_domain_for_local_non_halo_element[nh_count3++];
20932 
20933  // Include the element in the corresponding vector
20934  elements_to_send_pt[element_domain].push_back(ele_pt);
20935 
20936  // Get the number of nodes on the element
20937  const unsigned n_nodes = ele_pt->nnode();
20938  // Loop over the nodes
20939  for (unsigned j = 0; j < n_nodes; j++)
20940  {
20941  // Get each node of the element
20942  Node* node_pt = ele_pt->node_pt(j);
20943  // ... and associate it with element domains
20944  processors_associated_with_data_before_load_balance[node_pt].insert(
20945  element_domain);
20946 
20947  } // for (j < n_nodes)
20948 
20949  } // if (!(ele_pt->is_halo()))
20950 
20951  } // for (e < nelement_before_load_balance)
20952 
20953  // ... do the same for the halo elements (but do not add them to the
20954  // sending container since only the processor with the haloed
20955  // counterparts is in charge of that). Associate the nodes of the
20956  // halo elements with the processor they will live on
20957  for (unsigned iproc = 0; iproc < nproc; iproc++)
20958  {
20959  // There is no halo elements with myself
20960  if (iproc != my_rank)
20961  {
20962  // Get the number of halo elements with the "iproc" processor
20963  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20964  // Get the halo elements with the "iproc" processor
20965  Vector<GeneralisedElement*> halo_element_pt_iproc =
20966  this->root_halo_element_pt(iproc);
20967  // Loop over the halo elements with iproc
20968  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20969  {
20970  // Get the new domain for the halo element
20971  const unsigned element_domain = new_domains_halo_elements[iproc][ih];
20972 
20973  // Get the finite element
20974  FiniteElement* ele_pt =
20975  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20976 
20977  // Get the number of nodes on the halo element
20978  const unsigned n_nodes = ele_pt->nnode();
20979  // Loop over the nodes
20980  for (unsigned j = 0; j < n_nodes; j++)
20981  {
20982  // Get each node of the halo element
20983  Node* node_pt = ele_pt->node_pt(j);
20984 
20985  // ... and associate it with element domains
20986  processors_associated_with_data_before_load_balance[node_pt].insert(
20987  element_domain);
20988 
20989  } // for (j < n_nodes)
20990 
20991  } // for (ih < nhalo_ele_iproc)
20992 
20993  } // if (iproc != my_rank)
20994 
20995  } // for (iproc < nproc)
20996 
20997  // The time to prepare elements to send to other processors
20998  if (Print_timings_level_load_balance > 1)
20999  {
21000  oomph_info << "CPU for preparing elements to send to other processors "
21001  "(load balance) [3]: "
21002  << TimingHelpers::timer() - tt_start_prepare_element_to_send
21003  << std::endl;
21004  }
21005 
21006  // Now all the nodes are associated with the processor where the
21007  // element will live on. This is performed for the nonhalo and halo
21008  // elements
21009 
21010  // =====================================================================
21011  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
21012  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
21013  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
21014  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
21015  // =====================================================================
21016 
21017  // =====================================================================
21018  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21019  // CURRENT PROCESSOR
21020  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21021  // =====================================================================
21022 
21023  // Get the time to compute new local halo elements within all
21024  // processors
21025  double tt_start_compute_new_local_halo_elements = 0.0;
21026  if (Print_timings_level_load_balance > 1)
21027  {
21028  tt_start_compute_new_local_halo_elements = TimingHelpers::timer();
21029  }
21030 
21031  // Before sending the elements across compute the new local
21032  // halo/haloed elements of each processor. Each processor could have
21033  // elements that will be part of the new halo/haloed elements of
21034  // another processors, then these processors need to compute the
21035  // relations that may happen among these other processors
21036 
21037  // Example:
21038  // Processor 1 may have elements that will be sent to processor 3
21039  // and 4. These processors need to know about the new halo elements
21040  // betweeen them but at this moment only processor 1 can compute that
21041  // info., since it is the only one that currently has that info.
21042 
21043  // Store the new local-halo elements of each processor, the HALOED
21044  // elements are also stored in the container, only needs to INVERT
21045  // the indexes. For example, the HALO elements of processor 2 with
21046  // processor 3 are stored in new_local_halo_element_pt[2][3], and
21047  // the HALOED elements of processor 2 with processor 3 are stored in
21048  // new_local_halo_element_pt[3][2]. Notice that these are also the
21049  // halo elements of processor 3 with 2
21050 
21051  // How to identify the new local halo/haloed element: 1) Loop over
21052  // the element; 2) Only work with nonhalo elements; 3) If the
21053  // element is not assigned to the current processor (iproc) then
21054  // check; 4) Is one of its nodes assiociated to the iproc processor?
21055  // 5) If yes the element is a halo in the iproc processor whose
21056  // nonhalo counter part (haloed) lives in the domain assigned to the
21057  // element
21058  Vector<Vector<Vector<FiniteElement*>>> new_local_halo_element_pt(nproc);
21059 
21060  // Loop over the processors
21061  for (unsigned iproc = 0; iproc < nproc; iproc++)
21062  {
21063  // Resize the container
21064  new_local_halo_element_pt[iproc].resize(nproc);
21065 
21066  // Boolean to know which elements have been already added to the
21067  // new local halo scheme in "iproc"
21068  Vector<std::map<FiniteElement*, bool>> new_local_halo_already_added(
21069  nproc);
21070 
21071  // Go through all the elements and identify the new local halo
21072  // elements of "iproc"
21073  unsigned nh_count5 = 0;
21074  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21075  {
21076  // Get the element
21077  FiniteElement* ele_pt = this->finite_element_pt(e);
21078  // Only work with nonhalo elements
21079  if (!(ele_pt->is_halo()))
21080  {
21081  // Get the domain to which the current element is associated
21082  const unsigned ele_domain =
21083  target_domain_for_local_non_halo_element[nh_count5++];
21084  // If the current element is not associated to the "iproc"
21085  // processor then it could be a halo element
21086  if (ele_domain != iproc)
21087  {
21088  // Get the number of nodes
21089  const unsigned nnodes = ele_pt->nnode();
21090  // Loop over the nodes
21091  for (unsigned j = 0; j < nnodes; j++)
21092  {
21093  Node* node_pt = ele_pt->node_pt(j);
21094  // Check if the node is associated with the current
21095  // "iproc" processor
21096  std::set<unsigned>::iterator it =
21097  processors_associated_with_data_before_load_balance[node_pt]
21098  .find(iproc);
21099  // If it is found then the element is a halo-element
21100  if (it !=
21101  processors_associated_with_data_before_load_balance[node_pt]
21102  .end())
21103  {
21104  // Add the element as new local-halo element with the
21105  // "ele_domain" processor. The non-halo counterpart will
21106  // be located on "ele_domain" processor after sending
21107  // elements across
21108  if (!new_local_halo_already_added[ele_domain][ele_pt])
21109  {
21110  // The element is a halo element on "iproc" with
21111  // "ele_domain"
21112  new_local_halo_element_pt[iproc][ele_domain].push_back(
21113  ele_pt);
21114  // Mark as done
21115  new_local_halo_already_added[ele_domain][ele_pt] = true;
21116  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21117  } // One of the nodes lies on an element on the current
21118  // "iproc" processor
21119  } // for (j < nnodes)
21120  } // if (ele_domain != iproc)
21121  } // if (!(ele_pt->is_halo()))
21122  } // for (e < nelement_before_load_balance)
21123 
21124  // Now do the same with the halo elements, we need to find those
21125  // halo elements that continue being halo elements but possibly
21126  // with/on another processor. The pair of processors where a
21127  // possible shared boundary is created needs to be notified.
21128 
21129  // Example
21130  //
21131  // ---------------* *---------------
21132  // | |* *| |
21133  // | |* *| |
21134  // | New domain |* *| New domain | * Mark the position
21135  // | proc 1 |* *| proc 3 | of halo elements
21136  // | |* *| |
21137  // | |* *| |
21138  // ---------------* *---------------
21139  // Proc 1 Proc 2
21140 
21141  // Processor 1: The halo elements on processor 1 continue being halo ON
21142  // PROCESSOR 1, but now WITH PROCESSOR 3
21143 
21144  // Processor 2: The halo elements on processor 2 continue being
21145  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
21146 
21147  // The current processor (my_rank) also needs to consider the halo
21148  // elements that will be halo elements of other processor with
21149  // another processor. The case of processor 2
21150 
21151  // Loop over all the halo elements in the current processor and
21152  // check if they will be halo with the "iproc" processor
21153  for (unsigned jproc = 0; jproc < nproc; jproc++)
21154  {
21155  // There are no halo elements with myself (the old halo elements
21156  // were halo in the "my_rank" processor)
21157  if (jproc != my_rank)
21158  {
21159  // Get the number of halo elements with the "jproc" processor
21160  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
21161  // Get the halo elements with the "jproc" processor
21162  Vector<GeneralisedElement*> halo_element_pt_jproc =
21163  this->root_halo_element_pt(jproc);
21164  // ... and check if any of those elements is a new halo
21165  // element with the "iproc" processor
21166  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
21167  {
21168  // Get the new domain for the halo element
21169  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
21170 
21171  // If the current element is not associated to the "iproc"
21172  // processor then it could be a halo element on "iproc" with
21173  // "ele_domain".
21174 
21175  // NOTE OUTDATE: Check if the halo element is going to be
21176  // sent to this processor (my_rank), if that is the case
21177  // then we don't need to add it to the set of new halo
21178  // elements with any other processor since any possible
21179  // shared boundary will be created when checking for the
21180  // intersection of the sent and received elements
21181 
21182  // if (ele_domain != iproc && ele_domain != my_rank)
21183 
21184  // NOTE UPDATE: Only check if the halo element is not going
21185  // to be part of the iproc processor, not required to avoid
21186  // those halo elements whose domain is the current rank
21187  // (my_rank). When the shared boundaries are computed, these
21188  // last elements can not create a shared boundary since no
21189  // haloed elements (that shared an edge) are found for
21190  // them. By considering also those halo elements whose new
21191  // domain is the current one (commenting "ele_domain !=
21192  // my_rank") the current processor can compute shared
21193  // boundaries with the iproc processor with help of its old
21194  // halo elements but that will become nonhalo elements, in
21195  // fact they will become haloed elements The halo element is
21196  // not sent to the "element_domain" processor and is not
21197  // passed to the array used to create the new shared
21198  // boundaries "new_shared_boundary_element_pt" because of
21199  // its halo condition
21200  if (ele_domain != iproc)
21201  {
21202  // Get the finite element
21203  FiniteElement* ele_pt =
21204  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
21205  // Get the number of nodes on the halo element
21206  const unsigned nnodes = ele_pt->nnode();
21207  // Loop over the nodes
21208  for (unsigned j = 0; j < nnodes; j++)
21209  {
21210  // Get each node of the halo element
21211  Node* node_pt = ele_pt->node_pt(j);
21212 
21213  // Check if the node is associated with the "iproc"
21214  // processor
21215  std::set<unsigned>::iterator it =
21216  processors_associated_with_data_before_load_balance[node_pt]
21217  .find(iproc);
21218  // If it is found then the element is a halo-element
21219  if (it !=
21220  processors_associated_with_data_before_load_balance[node_pt]
21221  .end())
21222  {
21223  // Add the element as new local-halo element with
21224  // the "ele_domain" processor. The non-halo
21225  // counterpart will be located on "ele_domain"
21226  // processor. Because this is a old-halo element it
21227  // will not be sent to the "element_domain" processor
21228  if (!new_local_halo_already_added[ele_domain][ele_pt])
21229  {
21230  // The element is a halo element on "iproc" with
21231  // "ele_domain"
21232  new_local_halo_element_pt[iproc][ele_domain].push_back(
21233  ele_pt);
21234  new_local_halo_already_added[ele_domain][ele_pt] = true;
21235 
21236  // Break the for of the nodes, the element has been
21237  // already added to the new_local_halo_element_pt
21238  // structure
21239  break;
21240 
21241  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21242 
21243  } // One of the nodes lies on an element belonging to
21244  // "iproc" processor
21245 
21246  } // for (j < nnodes)
21247 
21248  } // if (ele_domain != iproc)
21249 
21250  } // for (jh < n_halo_ele_jproc)
21251 
21252  } // if (jproc != my_rank) // The old halo elements are halo
21253  // with other processors except with "my_rank"
21254 
21255  } // for (jproc < nproc): This is the one that goes for the halo
21256  // elements in the current processor to find the new halo
21257  // elements
21258 
21259  } // for (iproc < nproc)
21260 
21261  // Get the time to compute new local halo elements within all
21262  // processors
21263  if (Print_timings_level_load_balance > 1)
21264  {
21265  oomph_info
21266  << "CPU for computing new local halo elements (load balance) [4]: "
21267  << TimingHelpers::timer() - tt_start_compute_new_local_halo_elements
21268  << std::endl;
21269  }
21270 
21271  // =====================================================================
21272  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21273  // CURRENT PROCESSOR
21274  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21275  // =====================================================================
21276 
21277  // =====================================================================
21278  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21279  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21280  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21281  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21282  // ELEMENTS IN THE RECEIVED PROCESSOR
21283  // =====================================================================
21284 
21285  // Get the time to compute new local shared boundary elements
21286  double tt_start_compute_new_local_shd_bnd_ele = 0.0;
21287  if (Print_timings_level_load_balance > 1)
21288  {
21289  tt_start_compute_new_local_shd_bnd_ele = TimingHelpers::timer();
21290  }
21291 
21292  // Store the new local-shared boundary elements and the face indexes
21293  // The halo elements and halo face indexes
21294  Vector<Vector<Vector<FiniteElement*>>>
21295  new_local_halo_shared_boundary_element_pt(nproc);
21296  Vector<Vector<Vector<unsigned>>>
21297  new_local_halo_shared_boundary_element_face_index(nproc);
21298 
21299  // Allocate enough memory for the containers
21300  for (unsigned iproc = 0; iproc < nproc; iproc++)
21301  {
21302  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21303  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21304  } // for (iproc < nproc)
21305 
21306  // Get the elements that create the new local-halo-shared
21307  // boundaries, mark them and identify the face that lies on the
21308  // shared boundary. The new local-halo-shared boundary elements are
21309  // actually a sub-set of the halo elements of each processor with in
21310  // each processor
21311  for (unsigned iproc = 0; iproc < nproc; iproc++)
21312  {
21313  // Star from jproc = iproc + 1 to avoid double creation of shared
21314  // boundary elements, any shared boundary element identified
21315  // between processor "iproc" and "jproc" is also established as
21316  // shared boundary element between processor "jproc" and "iproc"
21317  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21318  {
21319  this->get_shared_boundary_elements_and_face_indexes(
21320  new_local_halo_element_pt[iproc][jproc],
21321  new_local_halo_element_pt[jproc][iproc],
21322  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21323  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21324  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21325  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21326  } // for (jproc < nproc)
21327  } // for (iproc < nproc)
21328 
21329  // The time to compute new local shared boundary elements
21330  if (Print_timings_level_load_balance > 1)
21331  {
21332  oomph_info << "CPU for computing new local shared boundary elements "
21333  "(load balance) [5]: "
21334  << TimingHelpers::timer() -
21335  tt_start_compute_new_local_shd_bnd_ele
21336  << std::endl;
21337  }
21338 
21339  // =====================================================================
21340  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21341  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21342  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21343  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21344  // THE RECEIVED PROCESSOR
21345  // =====================================================================
21346 
21347  // =====================================================================
21348  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21349  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21350  // =====================================================================
21351 
21352  // Get the time to send the elements to their new processor in
21353  // charge
21354  double tt_start_send_elements_to_other_processors = 0.0;
21355  if (Print_timings_level_load_balance > 1)
21356  {
21357  tt_start_send_elements_to_other_processors = TimingHelpers::timer();
21358  }
21359 
21360  // Sort the nodes on shared boundaries so that they have the same
21361  // order on all the shared boundaries, this is required to know the
21362  // possible shared nodes among processors
21363  this->sort_nodes_on_shared_boundaries();
21364 
21365  // Store the received elements from each processor
21366  Vector<Vector<FiniteElement*>> received_elements_pt(nproc);
21367 
21368  // The haloed elements and haloed face indexes, these store the
21369  // haloed elements received from "iproc" but that are haloed with
21370  // "jproc". The elements are received from "iproc" which was the
21371  // processor that computed the haloed relation of the "my_rank"
21372  // processor with "jproc"
21373  Vector<Vector<Vector<FiniteElement*>>>
21374  new_received_haloed_shared_boundary_element_pt(nproc);
21375  Vector<Vector<Vector<unsigned>>>
21376  new_received_haloed_shared_boundary_element_face_index(nproc);
21377 
21378  // Container where to store the nodes on shared boundaries not
21379  // associated with the processor that receives the elements/nodes
21380  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21381  Vector<Vector<Vector<std::map<unsigned, Node*>>>>
21382  other_proc_shd_bnd_node_pt(nproc);
21383  // Resize the container
21384  for (unsigned iproc = 0; iproc < nproc; iproc++)
21385  {
21386  // Resize the container
21387  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21388  for (unsigned jproc = 0; jproc < nproc; jproc++)
21389  {
21390  // Get the number of shared boundaries (OLD shared boundaries)
21391  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21392  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21393  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21394  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21395  } // for (jproc < nproc)
21396 
21397  } // for (iproc < nproc)
21398 
21399  // Store the global node names
21400  // global_node_name[x][ ][ ] Global node number
21401  // global_node_name[ ][x][ ] Global node names
21402  // global_node_name[ ][ ][x] Global node info.
21403  Vector<Vector<Vector<unsigned>>> global_node_names;
21404 
21405  // Creates a map between the node name and the index of the global
21406  // node so we can access all its node names
21407  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21408 
21409  // Store the global shared nodes pointers
21410  Vector<Node*> global_shared_node_pt;
21411 
21412  // Compute all the names of the nodes and fill in the
21413  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21414  // on this processor (my_rank) by looking over all their names
21415  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21416  global_node_names,
21417  node_name_to_global_index,
21418  global_shared_node_pt);
21419 
21420  // From the elements received from each processor, store the haloed
21421  // information of the element, it means, the processor with which it
21422  // is haloed and the haloed index with that processor
21423  Vector<Vector<std::map<unsigned, FiniteElement*>>>
21424  received_old_haloed_element_pt(nproc);
21425  // [x][][] : The receiver processor (the original processor)
21426  // [][x][] : The processor with which the receiver processor has
21427  // haloed elements
21428  // [][][x]: The haloed element number
21429 
21430  // Resize the container
21431  for (unsigned iproc = 0; iproc < nproc; iproc++)
21432  {
21433  received_old_haloed_element_pt[iproc].resize(nproc);
21434  } // for (iproc < nproc)
21435 
21436  // Go through all processors and send the corresponding elements to
21437  // each one
21438  for (unsigned iproc = 0; iproc < nproc; iproc++)
21439  {
21440  if (iproc != my_rank)
21441  {
21442  // -----------------------------------------------------------
21443  // Send (package) information of the elements
21444  // -----------------------------------------------------------
21445 
21446  // Keep track of the currently sent elements
21447  Vector<FiniteElement*> currently_sent_elements;
21448  // Keep track of the currently sent nodes to the iproc processor
21449  Vector<Node*> currently_sent_nodes;
21450 
21451  // Clear send and receive buffers
21452  Flat_packed_unsigneds.clear();
21453  Flat_packed_doubles.clear();
21454 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21455  Flat_packed_unsigneds_string.clear();
21456 #endif
21457 
21458  // Get the number of elements to send to iproc processor
21459  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21460 
21461  // The very first data of the flat package sent to processor
21462  // iproc is the number of elements that will be sent, this data
21463  // is used by the receiver processor to loop over the number of
21464  // expected elements to receive
21465  Flat_packed_unsigneds.push_back(nelements_to_send);
21466 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21467  std::stringstream junk;
21468  junk << "Number of elements to send from processor " << my_rank
21469  << " to processor " << iproc << ": (" << nelements_to_send << ")";
21470  Flat_packed_unsigneds_string.push_back(junk.str());
21471 #endif
21472 
21473  // Loop over the elements to sent
21474  for (unsigned e = 0; e < nelements_to_send; e++)
21475  {
21476  // Get the element to send
21477  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21478 
21479  // Get the current number of sent elements
21480  const unsigned ncurrently_sent_elements =
21481  currently_sent_elements.size();
21482 
21483  // Try to add the element
21484  const unsigned index_ele = try_to_add_element_pt_load_balance(
21485  currently_sent_elements, send_ele_pt);
21486 
21487  // Element needs to be added
21488  if (index_ele == ncurrently_sent_elements)
21489  {
21490  Flat_packed_unsigneds.push_back(1);
21491 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21492  Flat_packed_unsigneds_string.push_back(
21493  "Element needs to be constructed");
21494 #endif
21495 
21496  // Get required info. related with the element
21497  get_required_elemental_information_load_balance_helper(
21498  iproc, f_haloed_element_pt, send_ele_pt);
21499 
21500  // Get the number of nodes in the element
21501  const unsigned nnodes = send_ele_pt->nnode();
21502 
21503  // Loop over the nodes in the element
21504  for (unsigned j = 0; j < nnodes; j++)
21505  {
21506  Node* node_pt = send_ele_pt->node_pt(j);
21507 
21508  // Package the info. of the nodes
21509  add_node_load_balance_helper(iproc, // The destination process
21510  f_halo_element_pt,
21511  currently_sent_nodes,
21512  node_pt);
21513 
21514  } // for (j < nnodes)
21515 
21516  } // if (index_ele == ncurrently_sent_elements)
21517  else
21518  {
21519  Flat_packed_unsigneds.push_back(0);
21520 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21521  Flat_packed_unsigneds_string.push_back("Element already exists");
21522 #endif
21523  Flat_packed_unsigneds.push_back(index_ele);
21524 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21525  Flat_packed_unsigneds_string.push_back("Index of existing element");
21526 #endif
21527  } // else if (index_ele == ncurrently_sent_elements)
21528 
21529  } // for (e < nelements_to_send)
21530 
21531  // After storing the info. of the elements identify the indexes
21532  // of the "new_local_halo_shared_boundary_elements" in the
21533  // "currently_send_elements" vector, these elements will be
21534  // identified as "new_received_haloed_shared_boundary_elements"
21535  // on the "receiver" processor
21536 
21537  // Each processor has information of every other processor so we
21538  // need to send all the corresponding info. to the other
21539  // processors. Processor 1 may have information of the relation
21540  // (halo elements) between processor 3 and 4 say, so processor 1
21541  // needs to let know processor 3 and 4 what this relation is
21542  // (which are the shared-elements among these processors)
21543 
21544  for (unsigned jproc = 0; jproc < nproc; jproc++)
21545  {
21546  // Get the number of new local-halo shared boundary elements
21547  // between processor "jproc" and "iproc" (we invert the index
21548  // since we really want the haloed elements, those elements
21549  // that we have just sent)
21550  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21551  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21552 
21553  // The vector with the info. of the indexes
21554  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21555 
21556  // The number of found shared boundary elements in the sent
21557  // container (only consider the nonhalo elements)
21558  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21559  // The number of nonhalo elements in the new local halo shared
21560  // boundary elements
21561  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21562 
21563  // Loop over the local halo shared boundary elements between
21564  // processor jproc and iproc
21565  for (unsigned e = 0;
21566  e < njproc_iproc_new_local_halo_shared_boundary_ele;
21567  e++)
21568  {
21569  // Get the shared boundary element
21570  FiniteElement* shared_ele_pt =
21571  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21572 
21573  // Only consider the nonhalo elements since the halo
21574  // elements were no considered for sending
21575  if (!shared_ele_pt->is_halo())
21576  {
21577  nnon_halo_new_local_halo_shared_bound_ele++;
21578 
21579  // Now find the index on the currently sent elements
21580 
21581  // Get the current number of sent elements
21582  const unsigned ncurrently_sent_elements =
21583  currently_sent_elements.size();
21584  // Loop over the sent elements
21585  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21586  {
21587  FiniteElement* currently_sent_ele_pt =
21588  currently_sent_elements[ics];
21589 
21590  // Is this the element?
21591  if (currently_sent_ele_pt == shared_ele_pt)
21592  {
21593  // Store the index on the sent elements of the local
21594  // halo shared boundary element
21595  new_local_halo_shared_boundary_ele_index.push_back(ics);
21596  // Increase the number of found new local halo shared
21597  // bound element index
21598  nfound_new_local_halo_shared_bound_ele_index++;
21599  // We have found it, no need to further search
21600  break;
21601  } // if (currently_sent_ele_pt == shared_ele_pt)
21602 
21603  } // for (ics < ncurrently_sent_elements)
21604 
21605  } // if (!shared_ele_pt->is_halo())
21606 
21607  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21608 
21609 #ifdef PARANOID
21610  if (nfound_new_local_halo_shared_bound_ele_index !=
21611  nnon_halo_new_local_halo_shared_bound_ele)
21612  {
21613  std::ostringstream error_message;
21614  error_message << "Was only possible to identify ("
21615  << nfound_new_local_halo_shared_bound_ele_index
21616  << ") of ("
21617  << nnon_halo_new_local_halo_shared_bound_ele
21618  << ") shared "
21619  << "elements between\nprocessor (" << iproc
21620  << ") and (" << jproc << ") "
21621  << "when sending elements to processor (" << iproc
21622  << ")\n\n";
21623  throw OomphLibError(error_message.str(),
21624  OOMPH_CURRENT_FUNCTION,
21625  OOMPH_EXCEPTION_LOCATION);
21626  }
21627 #endif
21628 
21629  // Send a flag for synchronisation issues
21630  Flat_packed_unsigneds.push_back(9999);
21631 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21632  std::stringstream junk;
21633  junk << "Flag for synchronisation 9999";
21634  Flat_packed_unsigneds_string.push_back(junk.str());
21635 #endif
21636 
21637  // Send the number of nonhalo new local-shared boundary
21638  // elements of processor "iproc" with processor "jproc"
21639  Flat_packed_unsigneds.push_back(
21640  nnon_halo_new_local_halo_shared_bound_ele);
21641 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21642  std::stringstream junk2;
21643  junk2 << "Number of new local halo shared boundary elements "
21644  << nnon_halo_new_local_halo_shared_bound_ele;
21645  Flat_packed_unsigneds_string.push_back(junk2.str());
21646 #endif
21647 
21648  // Send the indexes and the face indexes of the shared
21649  // boundary elements
21650  unsigned counter_nonhalo_sent = 0;
21651  // Loop over the local halo shared boundary elements between
21652  // processor jproc and iproc
21653  for (unsigned e = 0;
21654  e < njproc_iproc_new_local_halo_shared_boundary_ele;
21655  e++)
21656  {
21657  // Get the shared boundary element
21658  FiniteElement* shared_ele_pt =
21659  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21660 
21661  // Only consider the nonhalo elements since the halo
21662  // elements were no considered for sending
21663  if (!shared_ele_pt->is_halo())
21664  {
21665  // Get the index on the sent elements of the current
21666  // nonhalo shared boundary element
21667  const unsigned ele_index =
21668  new_local_halo_shared_boundary_ele_index
21669  [counter_nonhalo_sent++];
21670  // ... and get the face index
21671  const unsigned face_index =
21672  new_local_halo_shared_boundary_element_face_index[jproc][iproc]
21673  [e];
21674 
21675  // Send the index on the sent elements of the new local
21676  // halo shared boundary element
21677  Flat_packed_unsigneds.push_back(ele_index);
21678 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21679  std::stringstream junk;
21680  junk << "The index of the halo shared boundary element "
21681  << ele_index;
21682  Flat_packed_unsigneds_string.push_back(junk.str());
21683 #endif
21684 
21685  // Send the face index of the new local halo shared boundary
21686  // element
21687  Flat_packed_unsigneds.push_back(face_index);
21688 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21689  std::stringstream junk2;
21690  junk2 << "The face index of the halo shared boundary element "
21691  << face_index;
21692  Flat_packed_unsigneds_string.push_back(junk2.str());
21693 #endif
21694 
21695  } // if (!shared_ele_pt->is_halo())
21696 
21697  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21698 
21699  } // for (jproc < nproc)
21700 
21701  // ----------------------------------------------------------
21702  // Send the info. perform the communications
21703  // ----------------------------------------------------------
21704  // Processor to which send the info.
21705  int send_proc = static_cast<int>(iproc);
21706  // Processor from which receive the info.
21707  int recv_proc = static_cast<int>(iproc);
21708  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21709 
21710  // ----------------------------------------------------------
21711  // Receive (unpackage) the info of the elements
21712  // ----------------------------------------------------------
21713 
21714  // Keep track of the currently created elements
21715  Vector<FiniteElement*> currently_created_elements;
21716  // Keep track of the currently created nodes
21717  Vector<Node*> currently_created_nodes;
21718 
21719  // Reset the counters
21720  Counter_for_flat_packed_doubles = 0;
21721  Counter_for_flat_packed_unsigneds = 0;
21722 
21723 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21724  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
21725  << " Number of elements need to be constructed "
21726  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
21727  << std::endl;
21728 #endif
21729 
21730  // Read the number of elements that need to be created
21731  const unsigned nelements_to_create =
21732  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21733 
21734  for (unsigned e = 0; e < nelements_to_create; e++)
21735  {
21736  // Create the element from received info. of "iproc"
21737  // processor on the current processor
21738  create_element_load_balance_helper(iproc,
21739  f_haloed_element_pt,
21740  received_old_haloed_element_pt,
21741  currently_created_elements,
21742  currently_created_nodes,
21743  other_proc_shd_bnd_node_pt,
21744  global_node_names,
21745  node_name_to_global_index,
21746  global_shared_node_pt);
21747  }
21748 
21749  // Copy the received elements from "iproc" processor
21750 
21751  // Number of received elements
21752  const unsigned nreceived_elements = currently_created_elements.size();
21753  received_elements_pt[iproc].resize(nreceived_elements);
21754  for (unsigned e = 0; e < nreceived_elements; e++)
21755  {
21756  received_elements_pt[iproc][e] = currently_created_elements[e];
21757  }
21758 
21759  // Go for the haloed elements received from processor "iproc"
21760  // but haloed with "jproc"
21761 
21762  // Allocate memory for the containers
21763  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21764  new_received_haloed_shared_boundary_element_face_index[iproc].resize(
21765  nproc);
21766 
21767  // Loop over the processors
21768  for (unsigned jproc = 0; jproc < nproc; jproc++)
21769  {
21770  // Read the synchronisation flag
21771  const unsigned synchronisation_flag =
21772  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21773 
21774  if (synchronisation_flag != 9999)
21775  {
21776  std::ostringstream error_message;
21777  error_message << "The synchronisation flag was not read, the\n"
21778  << "information sent between processor (" << my_rank
21779  << ") "
21780  << "and (" << iproc
21781  << ")\nis no longer synchronised\n\n";
21782  throw OomphLibError(error_message.str(),
21783  OOMPH_CURRENT_FUNCTION,
21784  OOMPH_EXCEPTION_LOCATION);
21785  }
21786 
21787  // Read the number of elements that will be part of the new
21788  // received haloed shared boundary elements received from "iproc"
21789  // and haloed with "jproc"
21790  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21791  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21792 
21793  // Loop over the new received haloed shared boundary elements
21794  for (unsigned e = 0;
21795  e < niproc_jproc_new_received_haloed_shared_boundary_ele;
21796  e++)
21797  {
21798  // Read the index of the new received haloed shared boundary
21799  // ele with "jproc"
21800  const unsigned ele_index =
21801  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21802  // Read the face index for the new received haloed shared
21803  // boundary element
21804  const unsigned face_index =
21805  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21806 
21807  // Get the element
21808  FiniteElement* shared_ele_pt =
21809  currently_created_elements[ele_index];
21810 
21811  // Add the element to the new received-haloed shared
21812  // boundary elements. Received from "iproc" but haloed with
21813  // "jproc" processor
21814  new_received_haloed_shared_boundary_element_pt[iproc][jproc]
21815  .push_back(shared_ele_pt);
21816  // Store the face index
21817  new_received_haloed_shared_boundary_element_face_index[iproc][jproc]
21818  .push_back(face_index);
21819 
21820  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21821 
21822  } // for (jproc < nproc)
21823 
21824  } // if (iproc != my_rank)
21825 
21826  } // for (iproc < nproc)
21827 
21828  // The time to send the elements to their new processor in charge
21829  if (Print_timings_level_load_balance > 1)
21830  {
21831  oomph_info << "CPU for sending elements to their new processors (load "
21832  "balance) [6]: "
21833  << TimingHelpers::timer() -
21834  tt_start_send_elements_to_other_processors
21835  << std::endl;
21836  }
21837 
21838  // =====================================================================
21839  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21840  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21841  // =====================================================================
21842 
21843  // =====================================================================
21844  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21845  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21846  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21847  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21848  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21849  // ELEMENTS)
21850  // =====================================================================
21851 
21852  // Get the time to compute any additional shared boundary
21853  double tt_start_compute_additional_shared_boundaries = 0.0;
21854  if (Print_timings_level_load_balance > 1)
21855  {
21856  tt_start_compute_additional_shared_boundaries = TimingHelpers::timer();
21857  }
21858 
21859  // Store any additional elements that may create a shared boundary,
21860  // after sending elements from one to other processor check for any
21861  // new possible shared boundaries
21862  Vector<Vector<FiniteElement*>> tmp_group1_shared_boundary_element_pt(nproc);
21863  Vector<Vector<unsigned>> tmp_group1_shared_boundary_element_face_index(
21864  nproc);
21865  Vector<Vector<FiniteElement*>> tmp_group2_shared_boundary_element_pt(nproc);
21866  Vector<Vector<unsigned>> tmp_group2_shared_boundary_element_face_index(
21867  nproc);
21868 
21869  // Compute any additional shared boundaries by checking the
21870  // intersection between the received elements from each processor
21871  // and the elements just sent to that processor, the lowest
21872  // processors number loops over its received elements and the
21873  // highest loops over its sent elements (halo elements that have
21874  // become part of the domain now can create shared boundaries with
21875  // other processor)
21876 
21877  // Note: These additional shared boundaries may be created by the
21878  // elements that previously were halo but now have become part of
21879  // the processor (the received elements), and the elements that were
21880  // previously part of the processor but now have become halo (a
21881  // subset of the sent-elements)
21882 
21883  // Then these new shared boundaries come from the intersection of
21884  // the new-haloed elements (received elements) and the new-halo
21885  // elements (sent elements). These could be computed previously (in
21886  // the computing of the local new-halo and local new-haloed elements
21887  // usign the info. of the new domains for the old halo elements),
21888  // however, it was decided to perform the computation here in order to
21889  // avoid the identification of the old halo element that was part of a
21890  // shared boundary in the set of just received elements
21891  for (unsigned iproc = 0; iproc < nproc; iproc++)
21892  {
21893  if (my_rank < iproc)
21894  {
21895  // Lowest processor loops over the received elements
21896  this->get_shared_boundary_elements_and_face_indexes(
21897  received_elements_pt[iproc],
21898  elements_to_send_pt[iproc],
21899  tmp_group1_shared_boundary_element_pt[iproc],
21900  tmp_group1_shared_boundary_element_face_index[iproc],
21901  tmp_group2_shared_boundary_element_pt[iproc],
21902  tmp_group2_shared_boundary_element_face_index[iproc]);
21903 
21904  } // if (my_rank < iproc)
21905  else if (my_rank > iproc)
21906  {
21907  // Highest processor loops over the sent elements
21908  this->get_shared_boundary_elements_and_face_indexes(
21909  elements_to_send_pt[iproc],
21910  received_elements_pt[iproc],
21911  tmp_group1_shared_boundary_element_pt[iproc],
21912  tmp_group1_shared_boundary_element_face_index[iproc],
21913  tmp_group2_shared_boundary_element_pt[iproc],
21914  tmp_group2_shared_boundary_element_face_index[iproc]);
21915 
21916  } // else if (my_rank > iproc)
21917 
21918  } // for (iproc < nproc)
21919 
21920  // The time to compute any additional shared boundary
21921  if (Print_timings_level_load_balance > 1)
21922  {
21923  oomph_info
21924  << "CPU for computing additional shared boundaries (load balance) [7]: "
21925  << TimingHelpers::timer() -
21926  tt_start_compute_additional_shared_boundaries
21927  << std::endl;
21928  }
21929 
21930  // =====================================================================
21931  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21932  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21933  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21934  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21935  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21936  // ELEMENTS)
21937  // =====================================================================
21938 
21939  // =====================================================================
21940  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21941  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21942  // =====================================================================
21943 
21944  // Get the time to sort shared boundaries
21945  double tt_start_sort_shared_boundaries = 0.0;
21946  if (Print_timings_level_load_balance > 1)
21947  {
21948  tt_start_sort_shared_boundaries = TimingHelpers::timer();
21949  }
21950 
21951  // Once computed the elements that create the shared boundaries,
21952  // sort them so that the shared boundaries are created at the same
21953  // order in both processors that define the shared boundary
21954 
21955  // The order is like this
21956 
21957  // Lowest processors
21958  // 1) Shared boundary elements received from processors (local in
21959  // other processors)
21960  // 2) Local shared boundary elements (do not include halo elements)
21961  // 3) Shared boundary elements by intersection (already sorted)
21962 
21963  // Highest processors
21964  // 1) Local shared boundary elements (do not include halo elements)
21965  // 2) Shared boundary elements received from processors (local in
21966  // other processors)
21967  // 3) Shared boundary elements by intersection (already sorted)
21968 
21969  Vector<Vector<FiniteElement*>> new_shared_boundary_element_pt(nproc);
21970  Vector<Vector<unsigned>> new_shared_boundary_element_face_index(nproc);
21971  for (unsigned iproc = 0; iproc < nproc; iproc++)
21972  {
21973  // Lower processor
21974  if (my_rank < iproc)
21975  {
21976  // Copy the elements received from processor "jproc" but that
21977  // are haloed with "iproc" processor
21978  for (unsigned jproc = 0; jproc < nproc; jproc++)
21979  {
21980  // Can not receive elements from itself
21981  if (jproc != my_rank)
21982  {
21983  // Get the number of elements to copy from received processors
21984  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21985  new_received_haloed_shared_boundary_element_pt[jproc][iproc]
21986  .size();
21987  for (unsigned e = 0; e < nrecvd_haloed_shared_bound_ele_jproc_iproc;
21988  e++)
21989  {
21990  // Get the element
21991  FiniteElement* ele_pt =
21992  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21993  // Get the face index
21994  const unsigned face_index =
21995  new_received_haloed_shared_boundary_element_face_index[jproc]
21996  [iproc]
21997  [e];
21998 
21999  // Add the elements to the containers
22000  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22001  new_shared_boundary_element_face_index[iproc].push_back(
22002  face_index);
22003 
22004  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
22005 
22006  } // if (jproc != my_rank)
22007 
22008  } // for (jproc < nproc)
22009 
22010  // Then the local shared haloed (invert the indexes to get the
22011  // haloed elements)
22012  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
22013  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
22014  for (unsigned e = 0; e < nlocal_haloed_shared_bound_ele_iproc_my_rank;
22015  e++)
22016  {
22017  // Get the element
22018  FiniteElement* ele_pt =
22019  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
22020  // Get the face index
22021  const unsigned face_index =
22022  new_local_halo_shared_boundary_element_face_index[iproc][my_rank]
22023  [e];
22024 
22025  // Only include the element if it is nonhalo (this may be an
22026  // old halo element that helped to indentify a shared boundary
22027  // with iproc)
22028  if (!ele_pt->is_halo())
22029  {
22030  // Add the elements to the containers
22031  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22032  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22033  } // if (!ele_pt->is_halo())
22034 
22035  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
22036 
22037  // ... and finally any additional shared boundary elements from
22038  // tmp_group1
22039  const unsigned ntmp_group1_shared_bound_ele_iproc =
22040  tmp_group1_shared_boundary_element_pt[iproc].size();
22041  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
22042  {
22043  // Get the element
22044  FiniteElement* ele_pt =
22045  tmp_group1_shared_boundary_element_pt[iproc][e];
22046  // Get the face index
22047  const unsigned face_index =
22048  tmp_group1_shared_boundary_element_face_index[iproc][e];
22049 
22050  // Add the elements to the containers
22051  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22052  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22053 
22054  } // for (e < ntmp_group1_shared_bound_ele_iproc)
22055 
22056  } // if (my_rank < iproc)
22057  // Highest processor
22058  else if (my_rank > iproc)
22059  {
22060  // Get the haloed elements first and then the elements received
22061  // from processor "jproc" but that are haloed with "iproc"
22062  // processor
22063 
22064  // Get the number of elements to copy from local elements
22065  // (invert the indexes to get the haloed elements)
22066  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
22067  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
22068  for (unsigned e = 0; e < nlocal_haloed_shared_bound_ele_iproc_my_rank;
22069  e++)
22070  {
22071  // Get the element
22072  FiniteElement* ele_pt =
22073  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
22074  // Get the face index
22075  const unsigned face_index =
22076  new_local_halo_shared_boundary_element_face_index[iproc][my_rank]
22077  [e];
22078 
22079  // Only include the element if it is nonhalo (this may be an
22080  // old halo element that helped to indentify a shared boundary
22081  // with iproc)
22082  if (!ele_pt->is_halo())
22083  {
22084  // Add the elements to the containers
22085  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22086  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22087  } // if (!ele_pt->is_halo())
22088 
22089  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
22090 
22091  for (unsigned jproc = 0; jproc < nproc; jproc++)
22092  {
22093  // Can not receive elements from itself
22094  if (jproc != my_rank)
22095  {
22096  // Then the received shared elements from "jproc" but haloed
22097  // with "iproc"
22098  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
22099  new_received_haloed_shared_boundary_element_pt[jproc][iproc]
22100  .size();
22101  for (unsigned e = 0; e < nrecvd_haloed_shared_bound_ele_jproc_iproc;
22102  e++)
22103  {
22104  // Get the element
22105  FiniteElement* ele_pt =
22106  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
22107  // Get the face index
22108  const unsigned face_index =
22109  new_received_haloed_shared_boundary_element_face_index[jproc]
22110  [iproc]
22111  [e];
22112 
22113  // Add the elements to the containers
22114  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22115  new_shared_boundary_element_face_index[iproc].push_back(
22116  face_index);
22117 
22118  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
22119 
22120  } // if (jproc != my_rank)
22121 
22122  } // for (jproc < nproc)
22123 
22124  // ... and finally any additional shared boundary elements from
22125  // tmp_group2
22126  const unsigned ntmp_group2_shared_bound_ele_iproc =
22127  tmp_group2_shared_boundary_element_pt[iproc].size();
22128  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
22129  {
22130  // Get the element
22131  FiniteElement* ele_pt =
22132  tmp_group2_shared_boundary_element_pt[iproc][e];
22133  // Get the face index
22134  const unsigned face_index =
22135  tmp_group2_shared_boundary_element_face_index[iproc][e];
22136 
22137  // Add the elements to the containers
22138  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22139  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22140 
22141  } // for (e < ntmp_group2_shared_bound_ele_iproc)
22142 
22143  } // else if (my_rank > iproc)
22144 
22145  } // for (iproc < nproc)
22146 
22147  // The time to sort shared boundaries
22148  if (Print_timings_level_load_balance > 1)
22149  {
22150  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
22151  << TimingHelpers::timer() - tt_start_sort_shared_boundaries
22152  << std::endl;
22153  }
22154 
22155  // =====================================================================
22156  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
22157  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
22158  // =====================================================================
22159 
22160  // =====================================================================
22161  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22162  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22163  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22164  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22165  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22166  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22167  // THE ORIGINAL BOUNDARIES
22168  // =====================================================================
22169  // Finally, create the new shared boundaries
22170 
22171  // Get the time to create the new shared boundaries
22172  double tt_start_create_new_shared_boundaries = 0.0;
22173  if (Print_timings_level_load_balance > 1)
22174  {
22175  tt_start_create_new_shared_boundaries = TimingHelpers::timer();
22176  }
22177 
22178  // Compute the elements that will remain after deletion in the
22179  // curent processor. This is required to check if the new shared
22180  // boundaries crete a connection with any node of the elements in
22181  // the boundaries
22182 
22183  // Try to use as much information as possible
22184 
22185  // Storage for the elements in the processor
22186  std::set<FiniteElement*> element_in_processor_pt;
22187 
22188  // Loop over the old elements, those before sending/received
22189  // elements to/from other processors
22190  unsigned nh_count6 = 0;
22191  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22192  {
22193  // Get the element
22194  FiniteElement* ele_pt = backed_up_ele_pt[e];
22195  // Only work with nonhalo elements
22196  if (!(ele_pt->is_halo()))
22197  {
22198  // Is the element part of the new domain
22199  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
22200  {
22201  // Add the element to the set of elements in the processor
22202  element_in_processor_pt.insert(ele_pt);
22203  }
22204 
22205  } // if (!(ele_pt->is_halo()))
22206 
22207  } // for (e < nelement_before_load_balance)
22208 
22209  // Now include the received elements from the other processors
22210  // Loop over the processors
22211  for (unsigned iproc = 0; iproc < nproc; iproc++)
22212  {
22213  // No elements received from myself
22214  if (iproc != my_rank)
22215  {
22216  // Get the number of received elements with the "iproc"
22217  // processor
22218  const unsigned n_received_ele = received_elements_pt[iproc].size();
22219  for (unsigned ie = 0; ie < n_received_ele; ie++)
22220  {
22221  // Get the ie-th received element from processor iproc
22222  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22223 
22224  // Include it in the set of elements in the processor
22225  element_in_processor_pt.insert(ele_pt);
22226 
22227  } // for (ie < nreceived_ele)
22228 
22229  } // if (iproc != my_rank)
22230 
22231  } // for (iproc < nproc)
22232 
22233  // Now create the shared boundaries
22234  create_new_shared_boundaries(element_in_processor_pt,
22235  new_shared_boundary_element_pt,
22236  new_shared_boundary_element_face_index);
22237 
22238  // The time to create the new shared boundaries
22239  if (Print_timings_level_load_balance > 1)
22240  {
22241  oomph_info
22242  << "CPU for creating new shared boundaries (load balance) [9]: "
22243  << TimingHelpers::timer() - tt_start_create_new_shared_boundaries
22244  << std::endl;
22245  }
22246 
22247  // =====================================================================
22248  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22249  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22250  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22251  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22252  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22253  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22254  // THE ORIGINAL BOUNDARIES
22255  // =====================================================================
22256 
22257  // =====================================================================
22258  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22259  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22260  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22261  // =====================================================================
22262 
22263  // Get the time to delete elements no longer belonging to the
22264  // processor
22265  double tt_start_delete_elements = 0.0;
22266  if (Print_timings_level_load_balance > 1)
22267  {
22268  tt_start_delete_elements = TimingHelpers::timer();
22269  }
22270 
22271  // Once computed the new shared boundaries delete the elements that
22272  // no longer belong to the processor (including the old halo
22273  // elements)
22274 
22275  // The procedure is similar to the one performed at the distribution
22276  // stage (src/generic/mesh.cc -- distribute() method)
22277 
22278  // Clean the storage for halo(ed) elements/nodes
22279  this->Halo_node_pt.clear();
22280  this->Root_halo_element_pt.clear();
22281 
22282  this->Haloed_node_pt.clear();
22283  this->Root_haloed_element_pt.clear();
22284 
22285  // Mark all the nodes as obsolete
22286  const unsigned nnodes = this->nnode();
22287  for (unsigned j = 0; j < nnodes; j++)
22288  {
22289  this->node_pt(j)->set_obsolete();
22290  }
22291 
22292  // Flush the mesh storage
22293  this->flush_element_storage();
22294 
22295  // Delete any storage of external elements and nodes
22296  this->delete_all_external_storage();
22297 
22298  // Clear external storage
22299  this->External_halo_node_pt.clear();
22300  this->External_halo_element_pt.clear();
22301 
22302  this->External_haloed_node_pt.clear();
22303  this->External_haloed_element_pt.clear();
22304 
22305  // Keep track of the deleted elements
22306  Vector<FiniteElement*> deleted_elements;
22307 
22308  // Delete the elements that no longer belong to the processor
22309  unsigned nh_count7 = 0;
22310  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22311  {
22312  FiniteElement* ele_pt = backed_up_ele_pt[e];
22313  // Only work with nonhalo elements
22314  if (!(ele_pt->is_halo()))
22315  {
22316  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22317  {
22318  // Add the element to the mesh
22319  this->add_element_pt(ele_pt);
22320  // Get the number of nodes on the element
22321  const unsigned nele_nodes = ele_pt->nnode();
22322  // Loop over the nodes of the element
22323  for (unsigned j = 0; j < nele_nodes; j++)
22324  {
22325  // Mark the node as non-obsolete
22326  ele_pt->node_pt(j)->set_non_obsolete();
22327  } // for (j < nele_nodes)
22328 
22329  } // The element belongs to the domain
22330  else
22331  {
22332  // Delete the element, but keep track of it
22333  deleted_elements.push_back(ele_pt);
22334  // Delete and point to null
22335  delete ele_pt;
22336  ele_pt = 0;
22337  }
22338 
22339  } // if (!(ele_pt->is_halo()))
22340  else
22341  {
22342  // If the element is halo, delete if but keep track of it
22343  deleted_elements.push_back(ele_pt);
22344  // Delete and point to null
22345  delete ele_pt;
22346  ele_pt = 0;
22347  }
22348 
22349  } // for (e < nelement_before_load_balance)
22350 
22351  // Now add the received elements from each processor
22352  for (unsigned iproc = 0; iproc < nproc; iproc++)
22353  {
22354  if (iproc != my_rank)
22355  {
22356  // Get the number of received elements with the "iproc"
22357  // processor
22358  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22359  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22360  {
22361  // Get the element and add it to the mesh
22362  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22363  // Add the element to the mesh
22364  this->add_element_pt(ele_pt);
22365  // Get the number of nodes on the element
22366  const unsigned nele_nodes = ele_pt->nnode();
22367  // Loop over the nodes of the element
22368  for (unsigned j = 0; j < nele_nodes; j++)
22369  {
22370  // Mark the node as non-obsolete
22371  ele_pt->node_pt(j)->set_non_obsolete();
22372  } // for (j < nele_nodes)
22373 
22374  } // for (ie < nreceived_ele)
22375 
22376  } // if (iproc != my_rank)
22377 
22378  } // for (iproc < nproc)
22379 
22380  // Now remove the obsolete nodes
22381  this->prune_dead_nodes();
22382 
22383  // The time to delete elements no longer belonging to the processor
22384  if (Print_timings_level_load_balance > 1)
22385  {
22386  oomph_info << "CPU for deleting elements no longer belonging to this "
22387  "processor (load balance) [10]: "
22388  << TimingHelpers::timer() - tt_start_delete_elements
22389  << std::endl;
22390  }
22391 
22392  // =====================================================================
22393  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22394  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22395  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22396  // =====================================================================
22397 
22398  // =====================================================================
22399  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22400  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22401  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22402  // ON EACH BOUNDARY
22403  // =====================================================================
22404 
22405  // Get the time to re-establish the halo(ed) information
22406  double tt_start_re_etablish_halo_ed_info = 0.0;
22407  if (Print_timings_level_load_balance > 1)
22408  {
22409  tt_start_re_etablish_halo_ed_info = TimingHelpers::timer();
22410  }
22411 
22412  // Prepare the data to re-establish the halo(ed) scheme
22413 
22414  // Sort the nodes on the new shared boundaries so that they have the
22415  // same order on all processors
22416  this->sort_nodes_on_shared_boundaries();
22417 
22418  // Before re-establish the halo and haloed elements save the number
22419  // of current elements in the boundaries, this will be useful to
22420  // re-establish the boundary elements. Notice that there may be
22421  // boundary elements with null pointers, since the element may no
22422  // longer belong to the current processor
22423  const unsigned tmp_nboundary = this->nboundary();
22424  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22425 
22426  // If there are regions, save the number of boundary-region elements
22427  Vector<Vector<unsigned>> ntmp_boundary_elements_in_region(tmp_nboundary);
22428  // Are there regions?
22429  const unsigned n_regions = this->nregion();
22430 
22431  // Loop over the boundaries
22432  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22433  {
22434  // Get the number of boundary elements
22435  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22436 
22437  // Resize the container
22438  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22439 
22440  // Loop over the regions
22441  for (unsigned rr = 0; rr < n_regions; rr++)
22442  {
22443  // Get the region id
22444  const unsigned region_id =
22445  static_cast<unsigned>(this->region_attribute(rr));
22446 
22447  // Store the number of element in the region (notice we are
22448  // using the region index not the region id to refer to the
22449  // region)
22450  ntmp_boundary_elements_in_region[ib][rr] =
22451  this->nboundary_element_in_region(ib, region_id);
22452 
22453  } // for (rr < n_regions)
22454 
22455  } // for (ib < tmp_nboundary)
22456 
22457  // Re-establish the halo(ed) scheme
22458  this->reset_halo_haloed_scheme();
22459 
22460  // Get the number of elements in the mesh after load balance
22461  const unsigned nelement_after_load_balance = this->nelement();
22462 
22463  // We need to reset boundary elements because we need to get rid of
22464  // the old boundary elements and stay only with the new ones
22465  this->reset_boundary_element_info(ntmp_boundary_elements,
22466  ntmp_boundary_elements_in_region,
22467  deleted_elements);
22468 
22469  // There is no need to re-set boundary coordinates since the
22470  // load-balanced mesh already has the correct information (the
22471  // boundary coordinate for each node was sent with the node
22472  // information)
22473 
22474  // We need to re-compute the number of segments on each boundary
22475  // after load balance. It may be possible that the boundary is now
22476  // split in more segments, or that previous gaps between the
22477  // segments have now dissapeared because the received elements
22478  // filled those gaps
22479 
22480  // In order to re-set the number of segments it is required to get
22481  // the face elements, attach them to create a contiguous
22482  // representation of the boundary (in segments possibly) and then
22483  // counter the number of segments. This can only be done after
22484  // restoring the boundary elements scheme (which has been done
22485  // above)
22486 
22487  // Set the number of segments for the boundaries with geom objects
22488  // associated. The correct value is not on the original mesh since
22489  // it is computed only when calling then
22490  // setup_boundary_coordinates() method (called only for those
22491  // boundaries with no geom object associated)
22492  for (unsigned b = 0; b < tmp_nboundary; b++)
22493  {
22494  if (this->boundary_geom_object_pt(b) != 0)
22495  {
22496  // Clear the boundary segment nodes storage
22497  this->flush_boundary_segment_node(b);
22498 
22499  // Dummy vector of nodes on segments
22500  Vector<Vector<Node*>> dummy_segment_node_pt;
22501 
22502  // Compute the new number of segments in the boundary
22503  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22504 
22505  // Get the number of segments from the vector of nodes
22506  const unsigned nsegments = dummy_segment_node_pt.size();
22507 
22508  // Set the number of segments for the storing of the nodes
22509  // associated to the segments
22510  this->set_nboundary_segment_node(b, nsegments);
22511  } // if (this->boundary_geom_object_pt(b)!=0)
22512 
22513  } // for (b < n_boundary)
22514 
22515  // The time to re-establish the halo(ed) information
22516  if (Print_timings_level_load_balance > 1)
22517  {
22518  oomph_info
22519  << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22520  << TimingHelpers::timer() - tt_start_re_etablish_halo_ed_info
22521  << std::endl;
22522  }
22523 
22524  // =====================================================================
22525  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22526  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22527  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22528  // BOUNDARY
22529  // =====================================================================
22530 
22531  if (Print_timings_level_load_balance > 1)
22532  {
22533  oomph_info << "CPU for load balance [n_ele_before="
22534  << nelement_before_load_balance
22535  << ", n_ele_after=" << nelement_after_load_balance << "]: "
22536  << TimingHelpers::timer() - t_start_overall_load_balance
22537  << std::endl;
22538  }
22539 
22540  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22541  }
22542 
22543  //======================================================================
22544  /// Use the first and second group of elements to find the
22545  /// intersection between them to get the shared boundary
22546  /// elements from the first and second group
22547  //======================================================================
22548  template<class ELEMENT>
22551  const Vector<FiniteElement*>& first_element_pt,
22552  const Vector<FiniteElement*>& second_element_pt,
22553  Vector<FiniteElement*>& first_shared_boundary_element_pt,
22554  Vector<unsigned>& first_shared_boundary_element_face_index,
22555  Vector<FiniteElement*>& second_shared_boundary_element_pt,
22556  Vector<unsigned>& second_shared_boundary_element_face_index)
22557  {
22558  // 1) Compare their faces (nodes) and if they match then they are
22559  // part of a shared boundary
22560  // 2) Save the first and second group of elements that give rise to
22561  // the shared boundary, also include the face index
22562 
22563  // Get the number of elements on the first group
22564  const unsigned nfirst_element = first_element_pt.size();
22565  // Loop over the elements in the first group
22566  for (unsigned ef = 0; ef < nfirst_element; ef++)
22567  {
22568  // Get the element
22569  FiniteElement* fele_pt = first_element_pt[ef];
22570  // Check if the element is halo
22571  bool first_ele_is_halo = false;
22572  if (fele_pt->is_halo())
22573  {
22574  first_ele_is_halo = true;
22575  }
22576  // Get each of the faces
22577  for (unsigned ifface = 0; ifface < 3; ifface++)
22578  {
22579  Vector<Node*> first_face(2);
22580  if (ifface == 0)
22581  {
22582  first_face[0] = fele_pt->node_pt(1);
22583  first_face[1] = fele_pt->node_pt(2);
22584  }
22585  else if (ifface == 1)
22586  {
22587  first_face[0] = fele_pt->node_pt(2);
22588  first_face[1] = fele_pt->node_pt(0);
22589  }
22590  else if (ifface == 2)
22591  {
22592  first_face[0] = fele_pt->node_pt(0);
22593  first_face[1] = fele_pt->node_pt(1);
22594  }
22595 
22596  // Now check each of the faces with the faces on the second
22597  // elements
22598 
22599  // Get the number of elements on the second group
22600  const unsigned nsecond_element = second_element_pt.size();
22601  // Loop over the elements in the second group
22602  for (unsigned es = 0; es < nsecond_element; es++)
22603  {
22604  // Get the element
22605  FiniteElement* sele_pt = second_element_pt[es];
22606  // Check if the element is halo
22607  bool second_ele_is_halo = false;
22608  if (sele_pt->is_halo())
22609  {
22610  second_ele_is_halo = true;
22611  }
22612  // Now check whether both elements are halo, if that is the
22613  // case then we go for the next elements. We can not look for
22614  // shared boundaries between halo elements since other
22615  // processors, those with the nonhalo counterpart of the
22616  // elements, are in charge of creating those shared boundaries
22617  if (!(first_ele_is_halo && second_ele_is_halo))
22618  {
22619  // Get each of the faces
22620  for (unsigned isface = 0; isface < 3; isface++)
22621  {
22622  Vector<Node*> second_face(2);
22623  if (isface == 0)
22624  {
22625  second_face[0] = sele_pt->node_pt(1);
22626  second_face[1] = sele_pt->node_pt(2);
22627  }
22628  else if (isface == 1)
22629  {
22630  second_face[0] = sele_pt->node_pt(2);
22631  second_face[1] = sele_pt->node_pt(0);
22632  }
22633  else if (isface == 2)
22634  {
22635  second_face[0] = sele_pt->node_pt(0);
22636  second_face[1] = sele_pt->node_pt(1);
22637  }
22638 
22639  // Now check for any intersection among first and second
22640  // faces
22641  if (first_face[0] == second_face[0] &&
22642  first_face[1] == second_face[1])
22643  {
22644  // Save the elements on the corresponding containers
22645  first_shared_boundary_element_pt.push_back(fele_pt);
22646  // .. and the face index
22647  first_shared_boundary_element_face_index.push_back(ifface);
22648 
22649  // Save the elements on the corresponding containers
22650  second_shared_boundary_element_pt.push_back(sele_pt);
22651  // .. and the face index
22652  second_shared_boundary_element_face_index.push_back(isface);
22653 
22654  // Break the loop over the faces of the first elements
22655  // and the first elements, we need to continue looking
22656  // on the next face of the first elements
22657 
22658  // Increase the indexes to force breaking the loop
22659  isface = 3;
22660  es = nsecond_element;
22661  }
22662  // Check for intersection with the reversed case too
22663  else if (first_face[0] == second_face[1] &&
22664  first_face[1] == second_face[0])
22665  {
22666  // Save the elements on the corresponding containers
22667  first_shared_boundary_element_pt.push_back(fele_pt);
22668  // .. and the face index
22669  first_shared_boundary_element_face_index.push_back(ifface);
22670 
22671  // Save the elements on the corresponding containers
22672  second_shared_boundary_element_pt.push_back(sele_pt);
22673  // .. and the face index
22674  second_shared_boundary_element_face_index.push_back(isface);
22675 
22676  // Break the loop over the faces of the first elements
22677  // and the first elements, we need to continue looking
22678  // on the next face of the first elements
22679 
22680  // Increase the indexes to force breaking the loop
22681  isface = 3;
22682  es = nsecond_element;
22683  }
22684 
22685  } // for (isface < 3)
22686 
22687  } // if (!(first_ele_is_halo && second_ele_is_halo))
22688 
22689  } // for (es < nsecond_element)
22690 
22691  } // for (ifface < 3)
22692 
22693  } // for (ef < nfirst_element)
22694  }
22695 
22696  //======================================================================
22697  /// \short Creates the new shared boundaries, this method is also in
22698  /// charge of computing the shared boundaries ids of each processor
22699  /// and send that info. to all the processors
22700  //======================================================================
22701  template<class ELEMENT>
22703  std::set<FiniteElement*>& element_in_processor_pt,
22704  Vector<Vector<FiniteElement*>>& new_shared_boundary_element_pt,
22705  Vector<Vector<unsigned>>& new_shared_boundary_element_face_index)
22706  {
22707  // Get the number of processors
22708  const unsigned nproc = this->communicator_pt()->nproc();
22709  // Get the rank of the current processor
22710  const unsigned my_rank = this->communicator_pt()->my_rank();
22711 
22712  // ================================================================
22713  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22714  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22715  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22716  // SAME EDGE (INTERNAL BOUNDARIES)
22717  // ================================================================
22718 
22719  // Get the time to get edges from shared boundary face elements
22720  double tt_start_get_edges_from_shd_bnd_face_ele = 0.0;
22721  if (Print_timings_level_load_balance > 2)
22722  {
22723  tt_start_get_edges_from_shd_bnd_face_ele = TimingHelpers::timer();
22724  }
22725 
22726  // Face elements that create the shared boundaries (unsorted)
22727  Vector<Vector<FiniteElement*>> tmp_unsorted_face_ele_pt(nproc);
22728  // The elements from where the face element was created
22729  Vector<Vector<FiniteElement*>> tmp_unsorted_ele_pt(nproc);
22730  // The face index of the bulk element from where was created the
22731  // face element
22732  Vector<Vector<int>> tmp_unsorted_face_index_ele(nproc);
22733 
22734  // Store the current edges lying on boundaries (this will help for
22735  // any edge of a shared boundary lying on an internal boundary)
22736  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22737 
22738  // Compute the edges on the other boundaries
22739  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22740 
22741  // Mark those edges (pair of nodes overlapped by a shared boundary)
22742  std::map<std::pair<Node*, Node*>, bool> overlapped_edge;
22743 
22744  // Associate every found edge (face element) on the shared boundary
22745  // with an original boundary only if the edge (face element) lies
22746  // (overlaps) on an original boundary, it may happen only for
22747  // internal boundaries
22748  Vector<Vector<int>> tmp_edge_boundary(nproc);
22749 
22750  // Get the face elements from the shared boundary elements with in
22751  // each processor
22752  for (unsigned iproc = 0; iproc < nproc; iproc++)
22753  {
22754  // There are no shared boundary elements with myself
22755  if (iproc != my_rank)
22756  {
22757  // Get the number of shared boundary elements with in "iproc"
22758  // processor
22759  const unsigned n_shared_bound_ele =
22760  new_shared_boundary_element_pt[iproc].size();
22761 
22762  // Avoid to create repeated face elements, compare the nodes on
22763  // the edges of the face elements
22764  Vector<std::pair<Node*, Node*>> done_faces;
22765 
22766  // Count the number of repeated faces
22767  unsigned nrepeated_faces = 0;
22768 
22769  // Loop over the shared boundary elements with the iproc
22770  // processor
22771  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22772  {
22773  // Get the bulk element
22774  FiniteElement* bulk_ele_pt =
22775  new_shared_boundary_element_pt[iproc][iele];
22776 
22777  // Get the face index
22778  int face_index = static_cast<int>(
22779  new_shared_boundary_element_face_index[iproc][iele]);
22780 
22781  // Create the face element
22782  FiniteElement* tmp_ele_pt =
22783  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
22784 
22785  // Before adding the face element to the vector check that is
22786  // not has been previously created
22787  bool done_face = false;
22788 
22789  // Get the number of nodes on the face element and get the first
22790  // and last node
22791  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22792  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22793  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22794 
22795  // Get the number of already done face elements
22796  const unsigned ndone_faces = done_faces.size();
22797  // Loop over the already visited face elements
22798  for (unsigned n = 0; n < ndone_faces; n++)
22799  {
22800  Node* first_done_face_node_pt = done_faces[n].first;
22801  Node* second_done_face_node_pt = done_faces[n].second;
22802  if (first_face_node_pt == first_done_face_node_pt &&
22803  last_face_node_pt == second_done_face_node_pt)
22804  {
22805  done_face = true;
22806  nrepeated_faces++;
22807  break;
22808  }
22809  // Check for the reversed case
22810  else if (first_face_node_pt == second_done_face_node_pt &&
22811  last_face_node_pt == first_done_face_node_pt)
22812  {
22813  done_face = true;
22814  nrepeated_faces++;
22815  break;
22816  }
22817 
22818  } // for (n < ndone_faces)
22819 
22820  // Only include the faces that are not repeated
22821  if (!done_face)
22822  {
22823  // Add the face element in the vector
22824  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22825  // Add the bulk element to the vector
22826  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22827  // Add the face index to the vector
22828  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22829  // Include the nodes in the done nodes vector
22830  std::pair<Node*, Node*> tmp_edge =
22831  std::make_pair(first_face_node_pt, last_face_node_pt);
22832  // Push the edge
22833  done_faces.push_back(tmp_edge);
22834 
22835  // Associate the face element with a boundary (if that is
22836  // the case)
22837  int edge_boundary_id = -1;
22838  std::map<std::pair<Node*, Node*>, unsigned>::iterator it;
22839  it = elements_edges_on_boundary.find(tmp_edge);
22840  // If the edges lie on a boundary then get the boundary id
22841  // on which the edges lie
22842  if (it != elements_edges_on_boundary.end())
22843  {
22844  // Assign the internal boundary id associated with the
22845  // edge
22846  edge_boundary_id = (*it).second;
22847  // Mark the edge as overlapped
22848  overlapped_edge[tmp_edge] = true;
22849  // Also include the reversed version of the edge
22850  std::pair<Node*, Node*> rev_tmp_edge =
22851  std::make_pair(last_face_node_pt, first_face_node_pt);
22852  // Mark the reversed version of the edge as overlapped
22853  overlapped_edge[rev_tmp_edge] = true;
22854  }
22855  else
22856  {
22857  // Look for the reversed version
22858  std::pair<Node*, Node*> rtmp_edge =
22859  std::make_pair(last_face_node_pt, first_face_node_pt);
22860  it = elements_edges_on_boundary.find(rtmp_edge);
22861  if (it != elements_edges_on_boundary.end())
22862  {
22863  // Assign the internal boundary id associated with the
22864  // edge
22865  edge_boundary_id = (*it).second;
22866  // Mark the edge as overlapped
22867  overlapped_edge[rtmp_edge] = true;
22868  // Mark the reversed version (normal) of the edge as
22869  // overlapped
22870  overlapped_edge[tmp_edge] = true;
22871  }
22872  }
22873  // Associate the edge with a boundary
22874  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22875  } // if (!done_face)
22876  else
22877  {
22878  // Delete the repeated face elements
22879  delete tmp_ele_pt;
22880  tmp_ele_pt = 0;
22881  }
22882 
22883  } // for (iele < n_shared_bound_ele)
22884 
22885  } // if (iproc != my_rank)
22886 
22887  } // for (iproc < nproc)
22888 
22889  // The time to get edges from shared boundary face elements
22890  if (Print_timings_level_load_balance > 2)
22891  {
22892  oomph_info << "CPU for getting edges from shared boundary face elements "
22893  "(load balance) [9.1]: "
22894  << TimingHelpers::timer() -
22895  tt_start_get_edges_from_shd_bnd_face_ele
22896  << std::endl;
22897  }
22898 
22899  // ================================================================
22900  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22901  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22902  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22903  // SAME EDGE (INTERNAL BOUNDARIES)
22904  // ================================================================
22905 
22906  // ================================================================
22907  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22908  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22909  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22910  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22911  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22912  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22913  // ================================================================
22914 
22915  // Get the time to sort shared face elements
22916  double tt_start_sort_shared_face_elements = 0.0;
22917  if (Print_timings_level_load_balance > 2)
22918  {
22919  tt_start_sort_shared_face_elements = TimingHelpers::timer();
22920  }
22921 
22922  // -----------------------------------------------------------------
22923  // Before continuing we need to ensured that the face elements are
22924  // stored in the same order in all processors. Sort them starting
22925  // from the face element with the bottom-left node coordinate
22926 
22927  // Face elements that create the shared boundaries (unsorted)
22928  Vector<Vector<FiniteElement*>> unsorted_face_ele_pt(nproc);
22929  // The elements from where the face element was created
22930  Vector<Vector<FiniteElement*>> unsorted_ele_pt(nproc);
22931  // The face index of the bulk element from where was created the
22932  // face element
22933  Vector<Vector<int>> unsorted_face_index_ele(nproc);
22934  // Associate every found edge on the shared boundary with an
22935  // original boundary only if the edge lies on an original boundary,
22936  // it may happen only for internal boundaries
22937  Vector<Vector<int>> edge_boundary(nproc);
22938 
22939  // For each face element, mark if the element should be considered
22940  // in its inverted way to fullfill with the bottom-left node to be
22941  // the first (left) node. First get the status of each element and
22942  // when they get sorted copy the values across
22943  std::vector<std::vector<bool>> tmp_treat_as_inverted(nproc);
22944  // Vector to store the status of the sorted face elements based on
22945  // the bottom-left condition
22946  std::vector<std::vector<bool>> treat_as_inverted(nproc);
22947 
22948  // Get the bottom-left node of each face element and sort them
22949  // starting from the face element with the bottom-left node
22950 
22951  // Loop over the processors
22952  for (unsigned iproc = 0; iproc < nproc; iproc++)
22953  {
22954  // There are no shared face elements with myself
22955  if (iproc != my_rank)
22956  {
22957  // Get the number of unsorted face elements
22958  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22959  // Store the centroid of the face element. Perform the sorting
22960  // based on the bottom-left centroid of each face element
22961  Vector<Vector<double>> centroid_vertices(n_face_ele);
22962 
22963  // Resize the storage for the treating as inverted face element
22964  // storage
22965  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22966 
22967  // Loop over the face elements associated with the iproc
22968  // processor
22969  for (unsigned e = 0; e < n_face_ele; e++)
22970  {
22971  // Get the face element
22972  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22973  // Get the number of nodes of the face element
22974  const unsigned n_node = face_ele_pt->nnode();
22975  Vector<double> bottom_left(2);
22976  // Assign as the bottom-left node the first node
22977  // Get the node
22978  Node* node_pt = face_ele_pt->node_pt(0);
22979  bottom_left[0] = node_pt->x(0);
22980  bottom_left[1] = node_pt->x(1);
22981  // Set as not treat as inverted element
22982  tmp_treat_as_inverted[iproc][e] = false;
22983  // Loop over the nodes to get the bottom-left vertex of all
22984  // the nodes
22985  for (unsigned n = 1; n < n_node; n++)
22986  {
22987  // Get the node
22988  Node* node_pt = face_ele_pt->node_pt(n);
22989  if (node_pt->x(1) < bottom_left[1])
22990  {
22991  bottom_left[0] = node_pt->x(0);
22992  bottom_left[1] = node_pt->x(1);
22993  // The first node is no longer the bottom-left node, we
22994  // need to treat the element as inverted
22995  tmp_treat_as_inverted[iproc][e] = true;
22996  } // if (node_pt->x(1) < bottom_left[1])
22997  else if (node_pt->x(1) == bottom_left[1])
22998  {
22999  if (node_pt->x(0) < bottom_left[0])
23000  {
23001  bottom_left[0] = node_pt->x(0);
23002  bottom_left[1] = node_pt->x(1);
23003  // The first node is no longer the bottom-left node, we
23004  // need to treat the element as inverted
23005  tmp_treat_as_inverted[iproc][e] = true;
23006  } // if (node_pt->x(0) < bottom_left[0])
23007  } // else if (node_pt->x(1) == bottom_left[1])
23008 
23009  } // for (n < n_node
23010 
23011  // Resize the container
23012  centroid_vertices[e].resize(2);
23013  // Add the centroid of the face element
23014  centroid_vertices[e][0] = (face_ele_pt->node_pt(0)->x(0) +
23015  face_ele_pt->node_pt(n_node - 1)->x(0)) *
23016  0.5;
23017  centroid_vertices[e][1] = (face_ele_pt->node_pt(0)->x(1) +
23018  face_ele_pt->node_pt(n_node - 1)->x(1)) *
23019  0.5;
23020 
23021  } // for (e < n_face_ele)
23022 
23023  // Sort the face elements based on their bottom-left node
23024  unsigned n_sorted_bottom_left = 0;
23025  // Keep track of the already sorted face elements
23026  std::vector<bool> done_face(n_face_ele, false);
23027 
23028  // Loop until all face elements have been sorted
23029  while (n_sorted_bottom_left < n_face_ele)
23030  {
23031  // The index of the next bottom-left face element
23032  unsigned index = 0;
23033  Vector<double> current_bottom_left(2);
23034  for (unsigned e = 0; e < n_face_ele; e++)
23035  {
23036  // Get the first not done face element
23037  if (!done_face[e])
23038  {
23039  // Store the first not done
23040  current_bottom_left[0] = centroid_vertices[e][0];
23041  current_bottom_left[1] = centroid_vertices[e][1];
23042  // Set the index
23043  index = e;
23044  // Break
23045  break;
23046  } // if (!done_face[e])
23047 
23048  } // for (e < n_face_ele)
23049 
23050  // Loop over all the other nondone face elements
23051  for (unsigned e = index + 1; e < n_face_ele; e++)
23052  {
23053  // Get the first not done face element
23054  if (!done_face[e])
23055  {
23056  if (centroid_vertices[e][1] < current_bottom_left[1])
23057  {
23058  // Re-set the current bottom left vertex
23059  current_bottom_left[0] = centroid_vertices[e][0];
23060  current_bottom_left[1] = centroid_vertices[e][1];
23061  // Re-assign the index
23062  index = e;
23063  } // if (centroid_vertices[e][1] < current_bottom_left[1])
23064  else if (centroid_vertices[e][1] == current_bottom_left[1])
23065  {
23066  if (centroid_vertices[e][0] < current_bottom_left[0])
23067  {
23068  // Re-set the current bottom left vertex
23069  current_bottom_left[0] = centroid_vertices[e][0];
23070  current_bottom_left[1] = centroid_vertices[e][1];
23071  // Re-assign the index
23072  index = e;
23073  } // if (centroid_vertices[e][0] < current_bottom_left[0])
23074 
23075  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
23076 
23077  } // if (!done_face[e])
23078 
23079  } // for (e < n_face_ele)
23080 
23081  // The face element
23082  unsorted_face_ele_pt[iproc].push_back(
23083  tmp_unsorted_face_ele_pt[iproc][index]);
23084  // The boundary element
23085  unsorted_ele_pt[iproc].push_back(tmp_unsorted_ele_pt[iproc][index]);
23086  // The face index
23087  unsorted_face_index_ele[iproc].push_back(
23088  tmp_unsorted_face_index_ele[iproc][index]);
23089  // The edge boundary associated to the face element
23090  edge_boundary[iproc].push_back(tmp_edge_boundary[iproc][index]);
23091  // The treat as inverted condition
23092  treat_as_inverted[iproc].push_back(
23093  tmp_treat_as_inverted[iproc][index]);
23094 
23095  // Mark the face element as sorted (done or visited)
23096  done_face[index] = true;
23097 
23098  // Increase the number of sorted bottom-left face elements
23099  n_sorted_bottom_left++;
23100 
23101  } // while (n_sorted_bottom_left < n_face_ele)
23102 
23103 #ifdef PARANOID
23104  // Get the number of face elements sorted with the bottom-left
23105  // condition
23106  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
23107 
23108  if (tmp_n_face_ele != n_face_ele)
23109  {
23110  std::ostringstream error_stream;
23111  error_stream
23112  << "The number of face elements before sorting them starting\n"
23113  << "from their bottom-left vertex is different from the number\n"
23114  << "of face elements after the sorting\n"
23115  << "N. ele before sorting: (" << n_face_ele << ")\n"
23116  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
23117  throw OomphLibError(
23118  error_stream.str(),
23119  "RefineableTriangleMesh::create_new_shared_boundaries()",
23120  OOMPH_EXCEPTION_LOCATION);
23121  }
23122 #endif
23123 
23124  } // if (iproc != my_rank)
23125 
23126  } // for (iproc < nproc)
23127 
23128  // The time to sort shared face elements
23129  if (Print_timings_level_load_balance > 2)
23130  {
23131  oomph_info << "CPU for sorting shared boundary face elements (load "
23132  "balance) [9.2]: "
23133  << TimingHelpers::timer() - tt_start_sort_shared_face_elements
23134  << std::endl;
23135  }
23136 
23137  // ================================================================
23138  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
23139  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
23140  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
23141  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
23142  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
23143  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
23144  // ================================================================
23145 
23146  // ================================================================
23147  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
23148  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
23149  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
23150  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
23151  // IS THE CASE)
23152  // ================================================================
23153 
23154  // Get the time to compute the valency of each node
23155  double tt_start_compute_valency_of_nodes = 0.0;
23156  if (Print_timings_level_load_balance > 2)
23157  {
23158  tt_start_compute_valency_of_nodes = TimingHelpers::timer();
23159  }
23160 
23161  // Stores the global-degree of each node
23162  std::map<Node*, unsigned> global_node_degree;
23163 
23164  // Get the global degree (valency) of each node
23165  compute_shared_node_degree_helper(unsorted_face_ele_pt, global_node_degree);
23166 
23167  // The time to compute the valency of each node
23168  if (Print_timings_level_load_balance > 2)
23169  {
23170  oomph_info
23171  << "CPU for computing the valency of nodes (load balance) [9.3]: "
23172  << TimingHelpers::timer() - tt_start_compute_valency_of_nodes
23173  << std::endl;
23174  }
23175 
23176  // ================================================================
23177  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
23178  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
23179  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
23180  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
23181  // IS THE CASE)
23182  // ================================================================
23183 
23184  // ================================================================
23185  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23186  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23187  // ================================================================
23188 
23189  // Get the time to compute nodes on non overlapped shared boundaries
23190  double tt_start_nodes_on_non_overlapped_shd_bnd = 0.0;
23191  if (Print_timings_level_load_balance > 2)
23192  {
23193  tt_start_nodes_on_non_overlapped_shd_bnd = TimingHelpers::timer();
23194  }
23195 
23196  // Mark the nodes on original boundaries not overlapped by shared
23197  // boundaries
23198  std::map<unsigned, std::map<Node*, bool>>
23199  node_on_bnd_not_overlapped_by_shd_bnd;
23200 
23201  // Loop over the edges of the original boundaries
23202  for (std::map<std::pair<Node*, Node*>, unsigned>::iterator it_map =
23203  elements_edges_on_boundary.begin();
23204  it_map != elements_edges_on_boundary.end();
23205  it_map++)
23206  {
23207  // Get the edge
23208  std::pair<Node*, Node*> edge_pair = (*it_map).first;
23209  // Is the edge overlaped by a shared boundary
23210  if (!overlapped_edge[edge_pair])
23211  {
23212  // Mark the nodes of the edge as being on an edge not overlaped
23213  // by a shared boundary on the boundary the edge is
23214  unsigned b = (*it_map).second;
23215 
23216  // Get the left node
23217  Node* left_node_pt = edge_pair.first;
23218  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
23219 
23220  // Get the right node
23221  Node* right_node_pt = edge_pair.second;
23222  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
23223 
23224  } // if (!overlapped_edge[edge_pair])
23225 
23226  } // Loop over edges to mark those nodes on overlaped edge by
23227  // shared boundaries
23228 
23229  // The time to compute nodes on non overlapped shared boundaries
23230  if (Print_timings_level_load_balance > 2)
23231  {
23232  oomph_info << "CPU for computing nodes on non overlapped shared "
23233  "boundaries (load balance) [9.4]: "
23234  << TimingHelpers::timer() -
23235  tt_start_nodes_on_non_overlapped_shd_bnd
23236  << std::endl;
23237  }
23238 
23239  // ================================================================
23240  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23241  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23242  // ================================================================
23243 
23244  // ==================================================================
23245  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23246  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23247  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23248  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23249  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23250  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23251  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23252  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23253  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23254  // ==================================================================
23255 
23256  // Get the time to sort shared boundaries face elements to create a
23257  // continuous representation of the boundary
23258  double tt_start_join_shd_bnd_face_ele = 0.0;
23259  if (Print_timings_level_load_balance > 2)
23260  {
23261  tt_start_join_shd_bnd_face_ele = TimingHelpers::timer();
23262  }
23263 
23264  // Face elements that create the shared boundaries (sorted)
23265  Vector<Vector<Vector<FiniteElement*>>> sorted_face_ele_pt(nproc);
23266 
23267  // Bulk elements that create the shared boundaries (sorted)
23268  Vector<Vector<Vector<FiniteElement*>>> sorted_ele_pt(nproc);
23269 
23270  // Face indexes of the bulk elements that create the shared
23271  // boundaries (sorted)
23272  Vector<Vector<Vector<int>>> sorted_face_index_ele(nproc);
23273 
23274  // Store the edge boundary id associated with a shared boundary (if
23275  // any, this apply for shared boundaries lying on internal
23276  // boundaries, then the shared boundary is marked as overlaping an
23277  // internal boundary)
23278  Vector<Vector<int>> edge_boundary_id(nproc);
23279 
23280  // Store the connection information obtained when joining the face
23281  // elements (used for connection purposes only)
23282  Vector<Vector<Vector<int>>> sorted_connection_info(nproc);
23283 
23284  // Store the local shared boundary id associated to the elements
23285  // that will give rise to the shared boundaries (used to compute the
23286  // global shared boundary id from the local shared boundary id)
23287  Vector<Vector<unsigned>> proc_local_shared_boundary_id(nproc);
23288 
23289  // Map that associates the local shared boundary id with the list of
23290  // nodes that create it
23291  std::map<unsigned, std::list<Node*>>
23292  local_shd_bnd_id_to_sorted_list_node_pt;
23293 
23294  // Local shared bouonday id (used to locally identify the lists of
23295  // nodes that create shared boundaries, it is also useful to
23296  // identify connections with shared boundaries)
23297  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23298 
23299  // Sort the face elements, using the nodes at its ends
23300 
23301  // Mark the done elements
23302  std::map<FiniteElement*, bool> done_ele;
23303 
23304  // Mark the inverted elements
23305  std::map<FiniteElement*, bool> is_inverted;
23306 
23307  // Sort the face elements to get the number of shared boundaries
23308  // with in each processor
23309  for (unsigned iproc = 0; iproc < nproc; iproc++)
23310  {
23311  // No face elements with myself
23312  if (iproc != my_rank)
23313  {
23314  // Get the number of unsorted face elements with the iproc
23315  // processor
23316  const unsigned nunsorted_face_ele = unsorted_face_ele_pt[iproc].size();
23317  // Count the number of sorted face elements
23318  unsigned nsorted_face_ele = 0;
23319 
23320  // Iterate until all the face elements have been sorted
23321  while (nsorted_face_ele < nunsorted_face_ele)
23322  {
23323  // Take the first nonsorted element an use it as root element,
23324  // add elements to the left and right until no more elements
23325  // left or until a stop condition is reached (connection,
23326  // boundary node)
23327 
23328 #ifdef PARANOID
23329  // Flag to indicate if a root element was found
23330  bool found_root_element = false;
23331 #endif
23332 
23333  // Index of the found root element
23334  unsigned root_index = 0;
23335 
23336  // List that contains the sorted face elements
23337  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23338 
23339  // List that contains the sorted elements
23340  std::list<FiniteElement*> tmp_sorted_ele_pt;
23341 
23342  // List that contains the sorted face indexes of the bulk
23343  // elements
23344  std::list<int> tmp_sorted_face_index_ele;
23345 
23346  // Storing for the sorting nodes extracted from the face
23347  // elements. The sorted nodes are used to identify connections
23348  // among new shared boundaries or original boundaries
23349  std::list<Node*> tmp_sorted_nodes_pt;
23350  // Clear the storage (just in case)
23351  tmp_sorted_nodes_pt.clear();
23352 
23353  // The initial and final nodes
23354  Node* initial_node_pt = 0;
23355  Node* final_node_pt = 0;
23356 
23357  // Store the original boundary id related with the root face
23358  // element (if there is one)
23359  int root_edge_bound_id = -1;
23360 
23361  // Loop over the unsorted face elements until a root element
23362  // is found
23363  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23364  {
23365  // Get a root element
23366  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23367  // Is the element already done?
23368  if (!done_ele[root_ele_pt])
23369  {
23370  // Get the edge boundary id associated with the edge (if
23371  // there is one)
23372  root_edge_bound_id = edge_boundary[iproc][e];
23373  // Add the face element to the list of sorted face
23374  // elements
23375  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23376  // Add the bulk element to the list of sorted elements
23377  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23378  // Add the face index to the list of sorted face index
23379  // elements
23380  tmp_sorted_face_index_ele.push_back(
23381  unsorted_face_index_ele[iproc][e]);
23382 
23383  // Get the nodes and state them as initial and final
23384  const unsigned nnodes = root_ele_pt->nnode();
23385  // Check if the face element should be treated as inverted
23386  if (!treat_as_inverted[iproc][e])
23387  {
23388  initial_node_pt = root_ele_pt->node_pt(0);
23389  final_node_pt = root_ele_pt->node_pt(nnodes - 1);
23390  }
23391  else
23392  {
23393  initial_node_pt = root_ele_pt->node_pt(nnodes - 1);
23394  final_node_pt = root_ele_pt->node_pt(0);
23395  }
23396  // Add both nodes to the list of sorted nodes
23397  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23398  tmp_sorted_nodes_pt.push_back(final_node_pt);
23399 
23400  // Mark the element as done
23401  done_ele[root_ele_pt] = true;
23402  // Check if the face element should be treated as inverted
23403  if (!treat_as_inverted[iproc][e])
23404  {
23405  // Mark the element as not inverted
23406  is_inverted[root_ele_pt] = false;
23407  }
23408  else
23409  {
23410  // Mark the element as inverted
23411  is_inverted[root_ele_pt] = true;
23412  }
23413  // Increase the counter for sorted face elements
23414  nsorted_face_ele++;
23415  // Set the root index
23416  root_index = e;
23417 #ifdef PARANOID
23418  // Set the flag of found root element
23419  found_root_element = true;
23420 #endif
23421  // Break the loop
23422  break;
23423 
23424  } // if (!done_ele[root_ele_pt])
23425 
23426  } // for (e < nunsorted_face_ele)
23427 
23428 #ifdef PARANOID
23429  if (!found_root_element)
23430  {
23431  std::ostringstream error_stream;
23432  error_stream
23433  << "It was not possible the found the root element\n\n";
23434  throw OomphLibError(error_stream.str(),
23435  OOMPH_CURRENT_FUNCTION,
23436  OOMPH_EXCEPTION_LOCATION);
23437  }
23438 #endif
23439 
23440  // New element added. Continue adding elements -- or nodes --
23441  // to the list of shared boundary elements while a new element
23442  // has been added to the list (we have just added the root
23443  // element)
23444  bool new_element_added = true;
23445 
23446  // Similarly that in the
23447  // "create_polylines_from_halo_elements_helper() method, we
23448  // extract the nodes (in order) that will create the shared
23449  // polyline, and also check for connections with the just
23450  // added face elements (nodes)
23451 
23452  // Flags to indicate at which end (of the sorted list of
23453  // boundary elements) the element was added (left or right)
23454  bool element_added_to_the_left = false;
23455  bool element_added_to_the_right = false;
23456 
23457  // Flag to indicate that the "left" node of the element added
23458  // to the left was found to be shared with another boundary
23459  bool connection_to_the_left = false;
23460 
23461  // Flag to indicate that the "right" node of the element added
23462  // to the right was found to be shared with another boundary
23463  bool connection_to_the_right = false;
23464 
23465  // Flag to stop the adding of elements (and nodes) to the
23466  // current shared boundary (because there are connections at
23467  // both ends)
23468  bool current_polyline_has_connections_at_both_ends = false;
23469 
23470  // Store the boundary ids of the polylines to connect (only
23471  // used when the polyline was found to have a connection)
23472  // -1: Indicates no connection
23473  // -2: Indicates connection with itself
23474  // -3: Indicates no connection BUT STOP adding elements
23475  // -because the node is a boundary node whose boundary is no
23476  // -currently part of the domain. Think in one of the corner
23477  // -nodes of a triangle touchin a boundary that does no longer
23478  // -exist
23479  // Any other value: Boundary id to connect
23480  int bound_id_connection_to_the_left = -1;
23481  int bound_id_connection_to_the_right = -1;
23482 
23483  // Get the global degree of the node (notice the local degree
23484  // has been updated to global degree)
23485  const unsigned initial_node_degree =
23486  global_node_degree[initial_node_pt];
23487 
23488  // Flag to indicate we are calling the method from a load
23489  // balance sub-rutine
23490  const bool called_for_load_balance = true;
23491 
23492  // Check if the nodes of the root element have connections
23493  // ... to the left
23494  bound_id_connection_to_the_left =
23495  this->check_connections_of_polyline_nodes(
23496  element_in_processor_pt,
23497  root_edge_bound_id,
23498  overlapped_edge,
23499  node_on_bnd_not_overlapped_by_shd_bnd,
23500  tmp_sorted_nodes_pt,
23501  local_shd_bnd_id_to_sorted_list_node_pt,
23502  initial_node_degree,
23503  initial_node_pt,
23504  called_for_load_balance);
23505 
23506  // If there is a stop condition then set the corresponding
23507  // flag
23508  if (bound_id_connection_to_the_left != -1)
23509  {
23510  connection_to_the_left = true;
23511  } // if (bound_id_connection_to_the_left != -1)
23512 
23513  // Get the global degree of the node (notice the local degree
23514  // has been updated to global degree)
23515  const unsigned final_node_degree = global_node_degree[final_node_pt];
23516 
23517  // ... and to the right
23518  bound_id_connection_to_the_right =
23519  this->check_connections_of_polyline_nodes(
23520  element_in_processor_pt,
23521  root_edge_bound_id,
23522  overlapped_edge,
23523  node_on_bnd_not_overlapped_by_shd_bnd,
23524  tmp_sorted_nodes_pt,
23525  local_shd_bnd_id_to_sorted_list_node_pt,
23526  final_node_degree,
23527  final_node_pt,
23528  called_for_load_balance);
23529 
23530  // If there is a stop condition then set the corresponding
23531  // flag
23532  if (bound_id_connection_to_the_right != -1)
23533  {
23534  connection_to_the_right = true;
23535  } // if (bound_id_connection_to_the_right != -1)
23536 
23537  // If the current shared boundary has connections at both ends
23538  // then stop the adding of elements (and nodes)
23539  if (connection_to_the_left && connection_to_the_right)
23540  {
23541  current_polyline_has_connections_at_both_ends = true;
23542  }
23543 
23544  // Continue searching for more elements to add if
23545  // 1) A new element was added at the left or right of the list
23546  // 2) There are more possible elements to add
23547  // 3) The nodes at the edges of the added element (left or
23548  // right) are not part of any other previous shared
23549  // boundary
23550  while (new_element_added && (nsorted_face_ele < nunsorted_face_ele) &&
23551  !current_polyline_has_connections_at_both_ends)
23552  {
23553  // Loop over the remaining elements and try to create a
23554  // contiguous set of face elements, start looking from the
23555  // root index. Any previous element should have been already
23556  // visited
23557  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23558  {
23559  // Reset the flags for added elements, to the left and right
23560  new_element_added = false;
23561  element_added_to_the_left = false;
23562  element_added_to_the_right = false;
23563 
23564  // Get the "e"-th element on the vector
23565  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23566  // Get the boundary id associated with the edge (if any)
23567  const int edge_bound_id = edge_boundary[iproc][e];
23568  // Check if the element has been already sorted and the
23569  // related edge bound id is the same as the root edge (if
23570  // any)
23571  if (!done_ele[tmp_ele_pt] &&
23572  (edge_bound_id == root_edge_bound_id))
23573  {
23574  // Get the number of nodes on the current element
23575  const unsigned nnodes = tmp_ele_pt->nnode();
23576  // Get the first and last node of the element
23577  // Check if the face element should be treated as inverted
23578  Node* first_node_pt = 0;
23579  Node* last_node_pt = 0;
23580  if (!treat_as_inverted[iproc][e])
23581  {
23582  first_node_pt = tmp_ele_pt->node_pt(0);
23583  last_node_pt = tmp_ele_pt->node_pt(nnodes - 1);
23584  }
23585  else
23586  {
23587  first_node_pt = tmp_ele_pt->node_pt(nnodes - 1);
23588  last_node_pt = tmp_ele_pt->node_pt(0);
23589  }
23590 
23591  // A pointer to the node at the left or right of the
23592  // just added element, the most left or the most right
23593  // node
23594  Node* new_added_node_pt = 0;
23595 
23596  // Check if the element goes to the left
23597  if (initial_node_pt == last_node_pt && !connection_to_the_left)
23598  {
23599  // Update the initial node and the just added node
23600  new_added_node_pt = initial_node_pt = first_node_pt;
23601  // Add the most left node
23602  tmp_sorted_nodes_pt.push_front(first_node_pt);
23603  // Add the face element to the list of sorted face
23604  // elements
23605  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23606  // Add the bulk element to the list of sorted elements
23607  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23608  // Add the face index to the list of sorted face index
23609  // elements
23610  tmp_sorted_face_index_ele.push_front(
23611  unsorted_face_index_ele[iproc][e]);
23612  if (!treat_as_inverted[iproc][e])
23613  {
23614  // Mark the element as not inverted
23615  is_inverted[tmp_ele_pt] = false;
23616  }
23617  else
23618  {
23619  // Mark the element as inverted
23620  is_inverted[tmp_ele_pt] = true;
23621  }
23622  // Set the flag to indicate a new element was added
23623  new_element_added = true;
23624  // Set the flag to indicate the element was added to
23625  // the left
23626  element_added_to_the_left = true;
23627  }
23628  // Check if the element goes to the left (but inverted)
23629  else if (initial_node_pt == first_node_pt &&
23630  !connection_to_the_left)
23631  {
23632  // Update the initial node and the just added node
23633  new_added_node_pt = initial_node_pt = last_node_pt;
23634  // Add the most left node
23635  tmp_sorted_nodes_pt.push_front(last_node_pt);
23636  // Add the face element to the list of sorted face
23637  // elements
23638  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23639  // Add the bulk element to the list of sorted elements
23640  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23641  // Add the face index to the list of sorted face index
23642  // elements
23643  tmp_sorted_face_index_ele.push_front(
23644  unsorted_face_index_ele[iproc][e]);
23645  if (!treat_as_inverted[iproc][e])
23646  {
23647  // Mark the element as inverted
23648  is_inverted[tmp_ele_pt] = true;
23649  }
23650  else
23651  {
23652  // Mark the element as not inverted
23653  is_inverted[tmp_ele_pt] = false;
23654  }
23655  // Set the flag to indicate a new element was added
23656  new_element_added = true;
23657  // Set the flag to indicate the element was added to
23658  // the left
23659  element_added_to_the_left = true;
23660  }
23661  // Check if the elements goes to the right
23662  else if (final_node_pt == first_node_pt &&
23663  !connection_to_the_right)
23664  {
23665  // Update the final node and the just added node
23666  new_added_node_pt = final_node_pt = last_node_pt;
23667  // Add the most right node
23668  tmp_sorted_nodes_pt.push_back(last_node_pt);
23669  // Add the face element to the list of sorted face
23670  // elements
23671  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23672  // Add the bulk element to the list of sorted elements
23673  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23674  // Add the face index to the list of sorted face index
23675  // elements
23676  tmp_sorted_face_index_ele.push_back(
23677  unsorted_face_index_ele[iproc][e]);
23678  if (!treat_as_inverted[iproc][e])
23679  {
23680  // Mark the element as not inverted
23681  is_inverted[tmp_ele_pt] = false;
23682  }
23683  else
23684  {
23685  // Mark the element as inverted
23686  is_inverted[tmp_ele_pt] = true;
23687  }
23688  // Set the flag to indicate a new element was added
23689  new_element_added = true;
23690  // Set the flag to indicate the element was added to
23691  // the right
23692  element_added_to_the_right = true;
23693  }
23694  // Check if the elements goes to the right (but inverted)
23695  else if (final_node_pt == last_node_pt &&
23696  !connection_to_the_right)
23697  {
23698  // Update the final node and the just added node
23699  new_added_node_pt = final_node_pt = first_node_pt;
23700  // Add the most right node
23701  tmp_sorted_nodes_pt.push_back(first_node_pt);
23702  // Add the face element to the list of sorted face
23703  // elements
23704  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23705  // Add the bulk element to the list of sorted elements
23706  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23707  // Add the face index to the list of sorted face index
23708  // elements
23709  tmp_sorted_face_index_ele.push_back(
23710  unsorted_face_index_ele[iproc][e]);
23711  if (!treat_as_inverted[iproc][e])
23712  {
23713  // Mark the element as inverted
23714  is_inverted[tmp_ele_pt] = true;
23715  }
23716  else
23717  {
23718  // Mark the element as not inverted
23719  is_inverted[tmp_ele_pt] = false;
23720  }
23721  // Set the flag to indicate a new elements was added
23722  new_element_added = true;
23723  // Set the flag to indicate the element was added to
23724  // the right
23725  element_added_to_the_right = true;
23726  }
23727 
23728  // Do additional stuff if the element was added
23729  if (new_element_added)
23730  {
23731  // Mark the element as done
23732  done_ele[tmp_ele_pt] = true;
23733  // Increase the counter for sorted face elements
23734  nsorted_face_ele++;
23735 
23736  // Get the global degree of the node (notice the
23737  // local degree has been updated to global degree)
23738  const unsigned new_added_node_degree =
23739  global_node_degree[new_added_node_pt];
23740 
23741  // Based on which side the element was added, look for
23742  // connections on that side
23743 
23744  // Verify for connections to the left (we need to
23745  // check for the connection variable too, since
23746  // after a connection has been done we no longer
23747  // need to verify for this condition)
23748  if (element_added_to_the_left && !connection_to_the_left)
23749  {
23750  // Check for connection
23751  bound_id_connection_to_the_left =
23752  this->check_connections_of_polyline_nodes(
23753  element_in_processor_pt,
23754  root_edge_bound_id,
23755  overlapped_edge,
23756  node_on_bnd_not_overlapped_by_shd_bnd,
23757  tmp_sorted_nodes_pt,
23758  local_shd_bnd_id_to_sorted_list_node_pt,
23759  new_added_node_degree,
23760  new_added_node_pt,
23761  called_for_load_balance);
23762 
23763  // If there is a stop condition then set the
23764  // corresponding flag
23765  if (bound_id_connection_to_the_left != -1)
23766  {
23767  connection_to_the_left = true;
23768  } // if (bound_id_connection_to_the_left != -1)
23769 
23770  } // if (node_added_to_the_left &&
23771  // !connection_to_the_left)
23772 
23773  // Verify for connections to the right (we need to
23774  // check for the connection variable too, since
23775  // after a connection has been done we no longer
23776  // need to verify for this condition)
23777  if (element_added_to_the_right && !connection_to_the_right)
23778  {
23779  // Check for connection
23780  bound_id_connection_to_the_right =
23781  this->check_connections_of_polyline_nodes(
23782  element_in_processor_pt,
23783  root_edge_bound_id,
23784  overlapped_edge,
23785  node_on_bnd_not_overlapped_by_shd_bnd,
23786  tmp_sorted_nodes_pt,
23787  local_shd_bnd_id_to_sorted_list_node_pt,
23788  new_added_node_degree,
23789  new_added_node_pt,
23790  called_for_load_balance);
23791 
23792  // If there is a stop condition then set the
23793  // corresponding flag
23794  if (bound_id_connection_to_the_right != -1)
23795  {
23796  connection_to_the_right = true;
23797  } // if (bound_id_connection_to_the_right != -1)
23798 
23799  } // if (node_added_to_the_right &&
23800  // !connection_to_the_right)
23801 
23802  // If the current shared boundary has connections at
23803  // both ends then stop the adding of elements (and
23804  // nodes)
23805  if (connection_to_the_left && connection_to_the_right)
23806  {
23807  current_polyline_has_connections_at_both_ends = true;
23808  }
23809 
23810  // Break the for (looping over unsorted face
23811  // elements) and re-start looking for more elements
23812  // that fit to the left or right
23813  break;
23814 
23815  } // if (new_element_added)
23816 
23817  } // if (!done_ele[tmp_ele_pt])
23818 
23819  } // for (e < nunsorted_face_ele)
23820 
23821  } // while(new_element_added &&
23822  // (nsorted_face_ele < nunsorted_face_ele)
23823  // && !current_polyline_has_connections_at_both_ends)
23824 
23825  // ------------------------------------------------------------
23826  // Before assigning a local shared boundary id to the list of
23827  // nodes and boundary elements, check for any loop that the
23828  // shared boundary may be creating
23829 
23830  // The vector of the elements
23831  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23832  // Store the list of elements on a vector of elements
23833  for (std::list<FiniteElement*>::iterator it =
23834  tmp_sorted_ele_pt.begin();
23835  it != tmp_sorted_ele_pt.end();
23836  it++)
23837  {
23838  tmp_vector_sorted_ele_pt.push_back((*it));
23839  }
23840 
23841  // The vector of the face elements
23842  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23843  // Store the list of face elements on a vector of face
23844  // elements
23845  for (std::list<FiniteElement*>::iterator it =
23846  tmp_sorted_face_ele_pt.begin();
23847  it != tmp_sorted_face_ele_pt.end();
23848  it++)
23849  {
23850  tmp_vector_sorted_face_ele_pt.push_back((*it));
23851  }
23852 
23853  // The vector of the face indexes
23854  Vector<int> tmp_vector_sorted_face_index_ele;
23855  // Store the list of elements on a vector of elements
23856  for (std::list<int>::iterator it = tmp_sorted_face_index_ele.begin();
23857  it != tmp_sorted_face_index_ele.end();
23858  it++)
23859  {
23860  tmp_vector_sorted_face_index_ele.push_back((*it));
23861  }
23862 
23863  // Store the nodes for the new shared polylines without loops
23864  Vector<std::list<Node*>> final_sorted_nodes_pt;
23865  // Store the boundary elements of the shared polyline without
23866  // loops
23867  Vector<Vector<FiniteElement*>> final_boundary_element_pt;
23868  // Store the boundary face elements of the shared polyline
23869  // without loops
23870  Vector<Vector<FiniteElement*>> final_boundary_face_element_pt;
23871  // Face indexes of the boundary elements without loops
23872  Vector<Vector<int>> final_face_index_element;
23873  // Connection flags (to the left) of the shared boundaries
23874  // without loops
23875  Vector<int> final_bound_id_connection_to_the_left;
23876  // Connection flags (to the right) of the shared boundaries
23877  // without loops
23878  Vector<int> final_bound_id_connection_to_the_right;
23879 
23880  // Break any possible loop created by the shared polyline
23881  this->break_loops_on_shared_polyline_load_balance_helper(
23882  local_shd_bnd_id,
23883  tmp_sorted_nodes_pt,
23884  tmp_vector_sorted_ele_pt,
23885  tmp_vector_sorted_face_ele_pt,
23886  tmp_vector_sorted_face_index_ele,
23887  bound_id_connection_to_the_left,
23888  bound_id_connection_to_the_right,
23889  final_sorted_nodes_pt,
23890  final_boundary_element_pt,
23891  final_boundary_face_element_pt,
23892  final_face_index_element,
23893  final_bound_id_connection_to_the_left,
23894  final_bound_id_connection_to_the_right);
23895 
23896  // Get the number of final sorted nodes
23897  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23898 
23899  // Loop over the list of final sorted nodes
23900  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23901  {
23902  // Store the list of nodes that gave rise to the shared
23903  // boundary
23904  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23905  final_sorted_nodes_pt[i];
23906 
23907  // Store the local shared boundary id assigned to the
23908  // elements that will create the shared boundary
23909  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23910 
23911  // Increase the shared boundary id (note that this is only
23912  // used to keep track of the list of nodes that create the
23913  // shared boundaries in the current processor)
23914  local_shd_bnd_id++;
23915 
23916  // Include the vector of elements to the sorted vector
23917  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23918 
23919  // Include the vector of face elements to the sorted vector
23920  sorted_face_ele_pt[iproc].push_back(
23921  final_boundary_face_element_pt[i]);
23922 
23923  // Include the vector of elements to the sorted vector
23924  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23925 
23926  // Include the possible associated boundary id to the vector
23927  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23928 
23929  // Include the connection information associated with the
23930  // current set of face elements (that will give rise to a
23931  // shared polyline
23932  // The temporal storage for the boundary connections ids
23933  Vector<int> bnd_connections_ids(2);
23934  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23935  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23936  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23937 
23938  } // for (i < n_final_sorted_nodes)
23939 
23940  } // while (nsorted_face_ele < nunsorted_face_ele)
23941 
23942  } // if (iproc != my_rank)
23943 
23944  } // for (iproc < nproc)
23945 
23946  // The time to sort shared boundaries face elements to create a
23947  // continuous representation of the boundary
23948  if (Print_timings_level_load_balance > 2)
23949  {
23950  oomph_info << "CPU for joining shared boundary face elements (load "
23951  "balance) [9.5]: "
23952  << TimingHelpers::timer() - tt_start_join_shd_bnd_face_ele
23953  << std::endl;
23954  }
23955 
23956  // ==================================================================
23957  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23958  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23959  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23960  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23961  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23962  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23963  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23964  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23965  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23966  // ==================================================================
23967 
23968  // ==================================================================
23969  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23970  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23971  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23972  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23973  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23974  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23975  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23976  // ALSO COMPUTED
23977  // ==================================================================
23978 
23979  // Get the time to compute new shared boundaries ids
23980  double tt_start_get_new_shared_boundaries_ids = 0.0;
23981  if (Print_timings_level_load_balance > 2)
23982  {
23983  tt_start_get_new_shared_boundaries_ids = TimingHelpers::timer();
23984  }
23985 
23986  // Get the number of shared boundaries with in each processor
23987  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23988  // Loop over the processors
23989  for (unsigned iproc = 0; iproc < nproc; iproc++)
23990  {
23991  // No shared boundaries with myself
23992  if (iproc != my_rank)
23993  {
23994  // Store the number of shared boundaries of the current
23995  // processor (my_rank) with the iproc processor
23996  nshared_boundaries_with_processor[iproc] =
23997  sorted_face_ele_pt[iproc].size();
23998 
23999  } // if (iproc != my_rank)
24000 
24001  } // for (iproc < nproc)
24002 
24003  // Each processor sends the number of shared boundaries that it has
24004  // with in each other processor to the "root_processor" which will
24005  // be in charge of checking and computing the global shared
24006  // boundaries ids
24007  const unsigned root_processor = 0;
24008 
24009  // Get the communicator of the mesh
24010  OomphCommunicator* comm_pt = this->communicator_pt();
24011 
24012  // Container where to store the info. received from other processor
24013  // in root. It receives from all processors the number of shared
24014  // boundaries that each one has with any other processor
24015  Vector<unsigned> flat_unsigned_root_received_data(nproc * nproc);
24016 
24017  // Gather the info. in the "root_processor"
24018  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
24019  // each processor
24020  nproc, // Total number of data to send from each
24021  // processor
24022  MPI_UNSIGNED,
24023  &flat_unsigned_root_received_data[0], // Container where
24024  // to receive the
24025  // info. from all
24026  // the processors
24027  nproc, // Number of data to receive from each processor
24028  MPI_UNSIGNED,
24029  root_processor, // The processor that receives all the
24030  // info.
24031  comm_pt->mpi_comm());
24032 
24033  // Container where root store the info. that will be sent back to
24034  // all processor, because root performs a Broadcast operation then
24035  // the info. is received in the same container
24036  Vector<unsigned> flat_unsigned_root_send_receive_data;
24037 
24038  // Compute the new initial and final shared boundary id (they are
24039  // based on the global number of shared boundaries)
24040  unsigned new_initial_shared_boundary_id = 0;
24041  unsigned new_final_shared_boundary_id = 0;
24042 
24043  // Compute the boundaries ids for the shared boundaries
24044  if (my_rank == root_processor)
24045  {
24046  // Change the representation of the data received from all
24047  // processors to a matrix representation for ease access
24048  Vector<Vector<unsigned>> root_nshared_bound_proc_with_proc(nproc);
24049  // Loop over the processors and get the number of shared
24050  // boundaries of processor iproc with jproc
24051  for (unsigned iproc = 0; iproc < nproc; iproc++)
24052  {
24053  // Resize the vector to store the data
24054  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
24055  // Loop over the processors and get the number of shared
24056  // boundaries of processor iproc with jproc
24057  for (unsigned jproc = 0; jproc < nproc; jproc++)
24058  {
24059  root_nshared_bound_proc_with_proc[iproc][jproc] =
24060  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
24061 
24062  } // for (jproc < nproc)
24063 
24064  } // for (iproc < nproc)
24065 
24066 #ifdef PARANOID
24067  // Check that the same number of boundaries are shared by two
24068  // specific processors
24069  for (unsigned iproc = 0; iproc < nproc; iproc++)
24070  {
24071  for (unsigned jproc = 0; jproc < iproc; jproc++)
24072  {
24073  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
24074  root_nshared_bound_proc_with_proc[jproc][iproc])
24075  {
24076  std::ostringstream error_stream;
24077  error_stream
24078  << "ROOT PROCESSOR ERROR\n\n"
24079  << "The number of shared boundaries between processor (" << iproc
24080  << ") and (" << jproc << ") is not the same:\n"
24081  << "Shared boundaries of processor (" << iproc
24082  << ") with processor (" << jproc << "): ("
24083  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
24084  << "Shared boundaries of processor (" << jproc
24085  << ") with processor (" << iproc << "): ("
24086  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
24087  throw OomphLibError(error_stream.str(),
24088  OOMPH_CURRENT_FUNCTION,
24089  OOMPH_EXCEPTION_LOCATION);
24090 
24091  } // The number of shared boundaries between processors
24092  // "iproc" and "jproc" is not the same
24093 
24094  } // for (jproc < iproc)
24095 
24096  } // for (iproc < nproc)
24097 #endif
24098 
24099  // The enumeration of the shared boundaries starts from the lowest
24100  // processor number to the highest processor number
24101 
24102  // Two processors share the same boundaries ids, the lowest
24103  // processor number is the one in charge of computing the shared
24104  // boundaries ids
24105  Vector<Vector<unsigned>> start_shared_bound_id_proc_with_proc(nproc);
24106  // Resize the vector, we can not do it when storing the
24107  // info. because of the strategy to save the info.
24108  for (unsigned iproc = 0; iproc < nproc; iproc++)
24109  {
24110  start_shared_bound_id_proc_with_proc[iproc].resize(nproc);
24111  }
24112 
24113  // The shared boundaries ids start from the current number of
24114  // original boundaries
24115  unsigned shared_bound_id = this->nboundary();
24116 
24117  // Set the new initial shared boundary id
24118  new_initial_shared_boundary_id = shared_bound_id;
24119 
24120  // Assign the global shared boundary id for the shared boundaries
24121  for (unsigned iproc = 0; iproc < nproc; iproc++)
24122  {
24123  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24124  {
24125  // Are there shared boundaries between the pair of processors
24126  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
24127  {
24128  // Set the start boundary id of processor "iproc" with
24129  // processor "jproc" and viceversa
24130  start_shared_bound_id_proc_with_proc[iproc][jproc] =
24131  shared_bound_id;
24132  start_shared_bound_id_proc_with_proc[jproc][iproc] =
24133  shared_bound_id;
24134  // Increase the shared boundary id counter with as many
24135  // shared boundaries there are between the iproc and jproc
24136  // processor
24137  shared_bound_id += root_nshared_bound_proc_with_proc[iproc][jproc];
24138  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
24139 
24140  } // for (jproc < iproc)
24141 
24142  } // for (iproc < nproc)
24143 
24144  // Set the new final shared boundary id
24145  new_final_shared_boundary_id = shared_bound_id;
24146 
24147  // Prepare the info. to send back to each processor
24148  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc * nproc);
24149 
24150  // Copy the info. to the storage to send the info. back to other
24151  // processors
24152  for (unsigned iproc = 0; iproc < nproc; iproc++)
24153  {
24154  for (unsigned jproc = 0; jproc < nproc; jproc++)
24155  {
24156  // Get the initial shared boundary id between each pair of
24157  // processors (iproc, jproc)
24158  const unsigned initial_shd_bnd_id =
24159  start_shared_bound_id_proc_with_proc[iproc][jproc];
24160  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
24161 
24162  // .. then copy the number of shared boundaries that there are
24163  // between processor iproc and jproc
24164  const unsigned nshared_bnd_iproc_jproc =
24165  root_nshared_bound_proc_with_proc[iproc][jproc];
24166  flat_unsigned_root_send_receive_data.push_back(
24167  nshared_bnd_iproc_jproc);
24168 
24169  } // for (jproc < nproc)
24170 
24171  } // for (iproc < nproc)
24172 
24173  // .. at the end of the data to send include the global initial
24174  // shared boundary id
24175  flat_unsigned_root_send_receive_data.push_back(
24176  new_initial_shared_boundary_id);
24177 
24178  // ... and the global final shared boundary id
24179  flat_unsigned_root_send_receive_data.push_back(
24180  new_final_shared_boundary_id);
24181 
24182  } // if (my_rank == root_processor)
24183 
24184  // Send the initial shared boundaries ids and the number of shared
24185  // boundaries between all procesors to all processors. All
24186  // processors need to know this info.
24187 
24188  // The number of data that will be sent by root to other processors
24189  // and the number of data that other processors receive from root,
24190  // it is the same because it is performed via a Broadcast
24191  unsigned root_ndata_sent_to_all_proc =
24192  flat_unsigned_root_send_receive_data.size();
24193 
24194  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
24195  1,
24196  MPI_UNSIGNED,
24197  root_processor,
24198  comm_pt->mpi_comm());
24199 
24200  // Resize the container if this is a processor that receives data
24201  if (my_rank != root_processor)
24202  {
24203  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
24204  }
24205 
24206  // Send back the start boundaries ids for the shared boundaries
24207  // Scatter the info. from the "root_processor"
24208  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
24209  // each
24210  // processor
24211  root_ndata_sent_to_all_proc, // Total number of data to
24212  // send to each processor
24213  MPI_UNSIGNED,
24214  root_processor, // The processor that sends all the info.
24215  comm_pt->mpi_comm());
24216 
24217  // The container to store the initial shared boundaries ids between
24218  // each pair of processors
24219  Vector<Vector<unsigned>> initial_shared_bound_id_proc_with_proc(nproc);
24220 
24221  // All processors need to know how many shared boundaries there are
24222  // between each pair of processors
24223 
24224  // The number of shared boundaries between each pair of processors
24225  Vector<Vector<unsigned>> nshared_bound_proc_with_proc(nproc);
24226 
24227  unsigned iflat_counter = 0;
24228  // Fill the containers with the received info. from root processor
24229  for (unsigned iproc = 0; iproc < nproc; iproc++)
24230  {
24231  // Resize the containers
24232  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
24233  nshared_bound_proc_with_proc[iproc].resize(nproc);
24234 
24235  // Loop over the processors
24236  for (unsigned jproc = 0; jproc < nproc; jproc++)
24237  {
24238  // Get the initial shared boundary id between each pair of
24239  // processors (iproc, jproc)
24240  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
24241  flat_unsigned_root_send_receive_data[iflat_counter++];
24242 
24243  // .. and copy the number of shared boundaries that there are
24244  // between processor iproc and jproc
24245  nshared_bound_proc_with_proc[iproc][jproc] =
24246  flat_unsigned_root_send_receive_data[iflat_counter++];
24247 
24248  } // for (jproc < nproc)
24249 
24250  } // for (iproc < nproc)
24251 
24252  // Read the new initial shared boundary id
24253  new_initial_shared_boundary_id =
24254  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc - 2];
24255 
24256  // Read the new final shared boundary id
24257  new_final_shared_boundary_id =
24258  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc - 1];
24259 
24260  // The time to compute new shared boundaries ids
24261  if (Print_timings_level_load_balance > 2)
24262  {
24263  oomph_info
24264  << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24265  << TimingHelpers::timer() - tt_start_get_new_shared_boundaries_ids
24266  << std::endl;
24267  }
24268 
24269  // ==================================================================
24270  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24271  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24272  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24273  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24274  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24275  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24276  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24277  // ==================================================================
24278 
24279  // ==================================================================
24280  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24281  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24282  // SHARED BOUNDARIES INFO.
24283  // ==================================================================
24284 
24285  // Get the time to create new shared boundaries representations
24286  double tt_start_create_new_shared_boundaries_polylines = 0.0;
24287  if (Print_timings_level_load_balance > 2)
24288  {
24289  tt_start_create_new_shared_boundaries_polylines = TimingHelpers::timer();
24290  }
24291 
24292  // Create the shared boundaries and establish all the related info.
24293  // - Create Polylines
24294  // - Store shared boundary elements
24295  // - Fill data structures to know which shared boundaries belong to
24296  // which processor
24297 
24298  // Resize the shared polylines container
24299  this->flush_shared_boundary_polyline_pt();
24300  this->Shared_boundary_polyline_pt.resize(nproc);
24301 
24302  // Resize for the boundaries ids shared with all processors
24303  this->Shared_boundaries_ids.clear();
24304  this->Shared_boundaries_ids.resize(nproc);
24305  for (unsigned iproc = 0; iproc < nproc; iproc++)
24306  {
24307  this->Shared_boundaries_ids[iproc].clear();
24308  this->Shared_boundaries_ids[iproc].resize(nproc);
24309  } // for (iproc < nproc)
24310 
24311  // Clear data
24312  this->Shared_boundary_from_processors.clear();
24313  this->Shared_boundary_overlaps_internal_boundary.clear();
24314  this->Boundary_was_splitted.clear();
24315  this->Boundary_subpolylines.clear();
24316  this->Boundary_marked_as_shared_boundary.clear();
24317 
24318  // Flush data
24319  this->flush_shared_boundary_element();
24320  this->flush_face_index_at_shared_boundary();
24321  this->flush_shared_boundary_node();
24322  this->flush_sorted_shared_boundary_node();
24323 
24324  // Store the old local inital shared boundary id (used to map from
24325  // local shared boundary id to global shared boundary id)
24326  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24327 
24328  // Update the initial and final shared boundary id
24329  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24330  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24331 
24332  // Storage for the new created polylines between the current
24333  // processor (my_rank) and the other processors, unsorted polylines
24334  Vector<TriangleMeshPolyLine*> unsorted_polylines_pt;
24335 
24336  // Map to get the global shared boundary id from the local shared
24337  // boundary id. Note that this is only used to get the global shared
24338  // boundary id when the shared boundary that is being created has
24339  // connections
24340  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24341 
24342  // Each processor knows the boundaries ids for each of the shared
24343  // boundaries it has, establish that info. in the proper containers
24344  // Additionally, store the shared boundaries of ALL processors with
24345  // ALL processors, but only create the shared boundaries (and their
24346  // respective polylines) of the current processor (my_rank)
24347  for (unsigned iproc = 0; iproc < nproc; iproc++)
24348  {
24349  // Avoid creating double shared boundaries, the shared boundaries
24350  // created between processor "iproc" and processor "jproc" are the
24351  // same than those created between processor "jproc" and processor
24352  // "iproc"
24353  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24354  {
24355  // If we are working with the current processor (my_rank) then
24356  // create the shared boundaries, if that is not the case then
24357  // only fill the info. on the proper containers
24358  if (iproc == my_rank || jproc == my_rank)
24359  {
24360  // Check the condition that made it get here
24361  unsigned ref_proc = 0;
24362  if (iproc == my_rank)
24363  {
24364  ref_proc = jproc;
24365  }
24366  else if (jproc == my_rank)
24367  {
24368  ref_proc = iproc;
24369  }
24370 
24371  // Get the number of shared boundaries between processor iproc
24372  // and processor jproc
24373  const unsigned nshared_bound_iproc_jproc =
24374  nshared_bound_proc_with_proc[iproc][jproc];
24375 
24376  // Loop over the number of shared boundaries
24377  for (unsigned counter = 0; counter < nshared_bound_iproc_jproc;
24378  counter++)
24379  {
24380  // Compute the shared boundary id for the shared boundary
24381  const unsigned shd_bnd_id =
24382  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24383  // Set up the shared boundaries between "iproc" (my_rank)
24384  // and "jproc"
24385  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24386  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24387 
24388  // Specify the processors involved for the creation of the
24389  // shared boundary
24390  Vector<unsigned> processors(2);
24391  processors[0] = iproc;
24392  processors[1] = jproc;
24393  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24394 
24395  // Get the possible root edge id associated to the shared
24396  // boundary (useful when the shared boundary overlaps an
24397  // original boundary)
24398  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24399  // Check if the shared boundary is overlapping (or is part)
24400  // of an internal boundary
24401  if (root_edge_bound_id != -1)
24402  {
24403  // If the shared boundary is part of an internal boundary then
24404  // mark the shared boundary
24405  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24406  static_cast<unsigned>(root_edge_bound_id);
24407  } // if (root_edge_bound_id != -1)
24408 
24409  // Storing for the nodes of the polyline (these are different
24410  // from the nodes on the face elements -- it is actually a
24411  // sub-set -- since the polyline is created from the first and
24412  // last nodes on the face elements)
24413  Vector<Node*> node_pt_to_create_shared_polyline;
24414 
24415  // Add the first node for the very first face element. In
24416  // the loop we will only add the last node of the face
24417  // element
24418  FiniteElement* first_face_ele_pt =
24419  sorted_face_ele_pt[ref_proc][counter][0];
24420 
24421  // Get the number of nodes on the first face element
24422  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24423  if (!is_inverted[first_face_ele_pt])
24424  {
24425  // Get the first node
24426  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24427  // Add the node to create the polyline
24428  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24429  // Add the first node to the shared boundary
24430  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24431  }
24432  else
24433  {
24434  // Get the first node in the inverted face element
24435  Node* first_node_pt =
24436  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24437  // Add the node to create the polyline
24438  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24439  // Add the first node to the shared boundary
24440  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24441  }
24442 
24443  // ... and extract only the last nodes of the face elements
24444  // in the next loop and add them in the vector of nodes to
24445  // create polylines (node_pt_to_create_shared_polyline)
24446 
24447  // Get the number of elements
24448  const unsigned nshared_boundary_elements =
24449  sorted_face_ele_pt[ref_proc][counter].size();
24450 
24451  // Store the shared boundary elements, nodes and get the
24452  // sorted nodes to create the polyline
24453  for (unsigned ie = 0; ie < nshared_boundary_elements; ie++)
24454  {
24455  // Get the bulk element version of the face element
24456  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24457 
24458  // Add the shared boundary element and associate it to the
24459  // "shd_bnd_id"
24460  this->add_shared_boundary_element(shd_bnd_id, bulk_ele_pt);
24461 
24462  // Get the face index from which the face element was
24463  // created from the bulk element
24464  const int face_index =
24465  sorted_face_index_ele[ref_proc][counter][ie];
24466 
24467  // Add the face index to the face indexes of the shared
24468  // boundary
24469  this->add_face_index_at_shared_boundary(shd_bnd_id, face_index);
24470 
24471  // Get the face element to obtain the last node
24472  FiniteElement* face_ele_pt =
24473  sorted_face_ele_pt[ref_proc][counter][ie];
24474 
24475  // Get the number of nodes
24476  const unsigned nnodes = face_ele_pt->nnode();
24477  if (!is_inverted[face_ele_pt])
24478  {
24479  // We have already added the first node, then start from
24480  // the second one
24481  for (unsigned n = 1; n < nnodes; n++)
24482  {
24483  // Get the node to be added
24484  Node* node_pt = face_ele_pt->node_pt(n);
24485  // Add the node and associate it to the shared boundary
24486  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24487  } // for (n < nnodes)
24488 
24489  // Add the last node of the face element to the vector of
24490  // nodes to create the polyline
24491  // Get the last node
24492  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24493  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24494  } // if (!is_inverted[face_ele_pt])
24495  else
24496  {
24497  // We have already added the first node, then start from
24498  // the second one (in reverse order)
24499  for (int n = nnodes - 2; n >= 0; n--)
24500  {
24501  // Get the node to be added
24502  Node* node_pt = face_ele_pt->node_pt(n);
24503  // Add the node and associate it to the shared boundary
24504  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24505  } // for (n < nnodes)
24506 
24507  // Add the last node of the face element to the vector of
24508  // nodes to create the polyline
24509  // Get the last node
24510  Node* last_node_pt = face_ele_pt->node_pt(0);
24511  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24512 
24513  } // else if (!is_inverted[face_ele_pt])
24514 
24515  } // for (ie < nshared_boundary_elements)
24516 
24517  // The number of nodes for the shared boundary polyline
24518  const unsigned nnodes_to_create_shared_boundary =
24519  node_pt_to_create_shared_polyline.size();
24520 
24521  // Get the vertices that create the shared boundary polyline
24522  Vector<Vector<double>> vertices(nnodes_to_create_shared_boundary);
24523  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24524  {
24525  vertices[n].resize(2);
24526  // Get the node
24527  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24528  // Get the vertices
24529  vertices[n][0] = tmp_node_pt->x(0);
24530  vertices[n][1] = tmp_node_pt->x(1);
24531  } // for (n < nnodes_to_create_shared_boundary)
24532 
24533  // Create the polyline
24534  TriangleMeshPolyLine* polyline_pt =
24535  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24536 
24537  // Updates bnd_id<--->curve section map
24538  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24539 
24540  // Add the new created polyline to the list of unsorted
24541  // polylines
24542  unsorted_polylines_pt.push_back(polyline_pt);
24543 
24544  // Mark the polyline for deletion (when calling destructor)
24545  this->Free_curve_section_pt.insert(polyline_pt);
24546 
24547  // Now assign the connection information
24548  // ---------------------------------------------------------
24549  // Get the local shared boundary id associated to the
24550  // elements that gave rise to this shared boundary
24551  const unsigned local_shd_bnd_id =
24552  proc_local_shared_boundary_id[ref_proc][counter];
24553 
24554  // Associate the local shared boundary to the global shared
24555  // boundary
24556  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24557 
24558  // Get the correct shared boundaries ids, from the local
24559  // shared boundaries ids established at the identification
24560  // of the conections
24561 
24562  // Get the local bnd id for the connection to the left
24563  int tmp_bnd_id_connection_to_the_left =
24564  sorted_connection_info[ref_proc][counter][0];
24565  // Get the local bnd id for the connection to the right
24566  int tmp_bnd_id_connection_to_the_right =
24567  sorted_connection_info[ref_proc][counter][1];
24568 
24569  // The global shared boundaries ids for connections to the
24570  // left or right
24571  int bnd_id_connection_to_the_left = -1;
24572  int bnd_id_connection_to_the_right = -1;
24573 
24574  // To the left
24575  // --------------
24576 
24577  // If the connection is with the same shared boundary then
24578  // set the current boundary id
24579  if (tmp_bnd_id_connection_to_the_left == -2)
24580  {
24581  // Set the current shared boundary id
24582  bnd_id_connection_to_the_left = shd_bnd_id;
24583  } // if (tmp_bnd_id_connection_to_the_left == -2)
24584 
24585  // Check if the connection was a stop adding nodes condition
24586  if (tmp_bnd_id_connection_to_the_left == -3)
24587  {
24588  // Set as no connected
24589  bnd_id_connection_to_the_left = -1;
24590  } // if (tmp_bnd_id_connection_to_the_left == -3)
24591 
24592  // There is a connection with another boundary, check if it
24593  // is a shared boundary or an original boundary
24594  if (tmp_bnd_id_connection_to_the_left >=
24595  static_cast<int>(old_local_shd_bnd_id))
24596  {
24597  // The connection is with a shared boundary, get the
24598  // global shared boundary id and set the connection
24599 #ifdef PARANOID
24600  std::map<unsigned, unsigned>::iterator it =
24601  local_to_global_shd_bnd_id.find(
24602  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24603  // If the global shared boundary id was not found we
24604  // are in trouble
24605  if (it == local_to_global_shd_bnd_id.end())
24606  {
24607  std::stringstream error_message;
24608  error_message
24609  << "The global shared boundary id was not found for\n"
24610  << "the local shared boundary shared with processor ("
24611  << ref_proc << ").\n"
24612  << "This processor: (" << my_rank << ")\n"
24613  << "Boundary shared with processor: (" << ref_proc << ")\n"
24614  << "Local shared boundary: ("
24615  << tmp_bnd_id_connection_to_the_left << ")\n";
24616  throw OomphLibError(error_message.str(),
24617  OOMPH_CURRENT_FUNCTION,
24618  OOMPH_EXCEPTION_LOCATION);
24619  } // if (it==local_to_global_shd_bnd_id.end())
24620 #endif
24621 
24622  // Get the global shared boundary id
24623  bnd_id_connection_to_the_left =
24624  local_to_global_shd_bnd_id[static_cast<unsigned>(
24625  tmp_bnd_id_connection_to_the_left)];
24626  }
24627  else
24628  {
24629  // The connection is with an original boundary, copy
24630  // the boundary id
24631  bnd_id_connection_to_the_left = tmp_bnd_id_connection_to_the_left;
24632 
24633  } // else (connection with a shared boundary)
24634 
24635  // To the right
24636  // --------------
24637 
24638  // If the connection is with the same shared boundary then
24639  // set the current boundary id
24640  if (tmp_bnd_id_connection_to_the_right == -2)
24641  {
24642  // Set the current shared boundary id
24643  bnd_id_connection_to_the_right = shd_bnd_id;
24644  } // if (tmp_bnd_id_connection_to_the_right == -2)
24645 
24646  // Check if the connection was a stop adding nodes condition
24647  if (tmp_bnd_id_connection_to_the_right == -3)
24648  {
24649  // Set as no connected
24650  bnd_id_connection_to_the_right = -1;
24651  } // if (tmp_bnd_id_connection_to_the_right == -3)
24652 
24653  // There is a connection with another boundary, check if it
24654  // is a shared boundary or an original boundary
24655  if (tmp_bnd_id_connection_to_the_right >=
24656  static_cast<int>(old_local_shd_bnd_id))
24657  {
24658  // The connection is with a shared boundary, get the
24659  // global shared boundary id and set the connection
24660 #ifdef PARANOID
24661  std::map<unsigned, unsigned>::iterator it =
24662  local_to_global_shd_bnd_id.find(
24663  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24664  // If the global shared boundary id was not found we
24665  // are in trouble
24666  if (it == local_to_global_shd_bnd_id.end())
24667  {
24668  std::stringstream error_message;
24669  error_message
24670  << "The global shared boundary id was not found for\n"
24671  << "the local shared boundary shared with processor ("
24672  << ref_proc << ").\n"
24673  << "This processor: (" << my_rank << ")\n"
24674  << "Boundary shared with processor: (" << ref_proc << ")\n"
24675  << "Local shared boundary: ("
24676  << tmp_bnd_id_connection_to_the_right << ")\n";
24677  throw OomphLibError(error_message.str(),
24678  OOMPH_CURRENT_FUNCTION,
24679  OOMPH_EXCEPTION_LOCATION);
24680  } // if (it==local_to_global_shd_bnd_id.end())
24681 #endif
24682  // Get the global shared boundary id
24683  bnd_id_connection_to_the_right =
24684  local_to_global_shd_bnd_id[static_cast<unsigned>(
24685  tmp_bnd_id_connection_to_the_right)];
24686  }
24687  else
24688  {
24689  // The connection is with an original boundary, copy the
24690  // boundary id
24691  bnd_id_connection_to_the_right =
24692  tmp_bnd_id_connection_to_the_right;
24693 
24694  } // else (connection with a shared boundary)
24695 
24696  // --------------------------------
24697  // Set the connection to the left
24698  if (bnd_id_connection_to_the_left != -1)
24699  {
24700  // Get the unsigned version of the boundary id to the left
24701  const unsigned ubnd_id_connection_to_the_left =
24702  static_cast<unsigned>(bnd_id_connection_to_the_left);
24703  // Set the initial vertex as connected
24704  polyline_pt->set_initial_vertex_connected();
24705  // Set the initial vertex connected boundary id
24706  polyline_pt->initial_vertex_connected_bnd_id() =
24707  ubnd_id_connection_to_the_left;
24708  // Set the chunk number to zero
24709  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24710 
24711  } // if (bnd_id_connection_to_the_left != -1)
24712 
24713  // ---------------------------------
24714  // Set the connection to the right
24715  if (bnd_id_connection_to_the_right != -1)
24716  {
24717  // Get the unsigned version of the boundary id to the
24718  // right
24719  const unsigned ubnd_id_connection_to_the_right =
24720  static_cast<unsigned>(bnd_id_connection_to_the_right);
24721  // Set the final vertex as connected
24722  polyline_pt->set_final_vertex_connected();
24723  // Set the final vertex connected boundary id
24724  polyline_pt->final_vertex_connected_bnd_id() =
24725  ubnd_id_connection_to_the_right;
24726  // Set the chunk number to zero
24727  polyline_pt->final_vertex_connected_n_chunk() = 0;
24728 
24729  } // if (bnd_id_connection_to_the_right != -1)
24730 
24731  } // for (counter < nshared_bound_iproc_jproc)
24732 
24733  } // if (iproc == my_rank || jproc == my_rank)
24734  else
24735  {
24736  // We are not working with the current processor, then we only
24737  // need to fill the containers
24738 
24739  // Get the number of shared boundaries between processor iproc
24740  // and processor jproc
24741  const unsigned nshared_bound_iproc_jproc =
24742  nshared_bound_proc_with_proc[iproc][jproc];
24743  // Loop over the number of shared boundaries
24744  for (unsigned counter = 0; counter < nshared_bound_iproc_jproc;
24745  counter++)
24746  {
24747  // Compute the shared boundary id for the shared boundary
24748  const unsigned shd_bnd_id =
24749  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24750 
24751  // Set up the shared boundaries between "iproc" and "jproc"
24752  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24753  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24754 
24755  // Specify the processors involved for the creation of the
24756  // shared boundary
24757  Vector<unsigned> processors(2);
24758  processors[0] = iproc;
24759  processors[1] = jproc;
24760  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24761 
24762  } // for (counter < nshared_bound_iproc_jproc)
24763 
24764  } // else if (iproc == my_rank || jproc == my_rank)
24765 
24766  } // for (jproc < nproc)
24767 
24768  } // for (iproc < nproc)
24769 
24770  // Get the time to create new shared boundaries representations
24771  if (Print_timings_level_load_balance > 2)
24772  {
24773  oomph_info << "CPU for creating new shared boundaries representations "
24774  "(load balance) [9.7]: "
24775  << TimingHelpers::timer() -
24776  tt_start_create_new_shared_boundaries_polylines
24777  << std::endl;
24778  }
24779 
24780  // ==================================================================
24781  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24782  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24783  // SHARED BOUNDARIES INFO.
24784  // ==================================================================
24785 
24786  // ==================================================================
24787  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24788  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24789  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24790  // ELEMENTS
24791  // ==================================================================
24792 
24793  // Get the time to create the new shared curves
24794  double tt_start_create_new_shared_curves = 0.0;
24795  if (Print_timings_level_load_balance > 2)
24796  {
24797  tt_start_create_new_shared_curves = TimingHelpers::timer();
24798  }
24799 
24800  // Sort the polylines and find if they create a contiguous open
24801  // curve
24802  if (unsorted_polylines_pt.size() > 0)
24803  {
24804  // Now that we have all the new unsorted polylines on "my_rank"x
24805  // processor it is time to sort them so they be all contiguous
24806  this->sort_polylines_helper(unsorted_polylines_pt,
24807  this->Shared_boundary_polyline_pt[my_rank]);
24808  }
24809 
24810  // Free the memory allocated for the face elements
24811  for (unsigned iproc = 0; iproc < nproc; iproc++)
24812  {
24813  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24814  for (unsigned e = 0; e < nface_ele; e++)
24815  {
24816  delete unsorted_face_ele_pt[iproc][e];
24817  unsorted_face_ele_pt[iproc][e] = 0;
24818  } // for (e < nface_ele)
24819 
24820  } // for (iproc < nproc)
24821 
24822  // The time to create the new shared curves
24823  if (Print_timings_level_load_balance > 2)
24824  {
24825  oomph_info
24826  << "CPU for creating the new shared curves (load balance) [9.8]: "
24827  << TimingHelpers::timer() - tt_start_create_new_shared_curves
24828  << std::endl;
24829  }
24830 
24831  // ==================================================================
24832  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24833  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24834  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24835  // ELEMENTS
24836  // ==================================================================
24837  }
24838 
24839  //======================================================================
24840  // Computes the degree of the nodes on the shared boundaries, the
24841  // degree of the node is computed from the global graph created by the
24842  // shared boundaries of all processors
24843  //======================================================================
24844  template<class ELEMENT>
24846  Vector<Vector<FiniteElement*>>& unsorted_face_ele_pt,
24847  std::map<Node*, unsigned>& global_node_degree)
24848  {
24849  // Get the rank and number of processors
24850  const unsigned nproc = this->communicator_pt()->nproc();
24851  const unsigned my_rank = this->communicator_pt()->my_rank();
24852 
24853  // Store a temporary sorting of the nodes, starting from the
24854  // lower-left position
24855  Vector<Vector<Node*>> tmp_sorted_shared_node_pt(nproc);
24856 
24857  // Store the alias of the node, it may be shared by more than two
24858  // processors, they should know that the node is the same
24859  // [0] iproc, processor with which the current processor shared the node
24860  // [1] node #, number of node in the number of nodes shared with iproc
24861  // processor
24862  std::map<Node*, Vector<Vector<unsigned>>> node_alias;
24863 
24864  // Stores the local adjacency matrix
24865  // (nproc*n_shared_nodes*n_shared_nodes)
24866  Vector<Vector<Vector<unsigned>>> local_adjacency_matrix(nproc);
24867 
24868  // Sort the nodes and create the adjacency matrix of each sub-graph
24869  // created by the shared edges
24870  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24871  tmp_sorted_shared_node_pt,
24872  node_alias,
24873  local_adjacency_matrix);
24874 
24875  // Prepare the info. to be sent to the root processor, which will be
24876  // in charge of updating the nodes degree by combining the info. of
24877  // all the processors
24878 
24879  // The flat package with the info. to send to root
24880  Vector<unsigned> package_unsigned_send_data_to_root;
24881 
24882  // Encode the info. that will be sent to the root processor
24883 
24884  // Loop over the temporary sorted nodes between each pair of
24885  // processors
24886  for (unsigned iproc = 0; iproc < nproc; iproc++)
24887  {
24888  // Send the processor index
24889  package_unsigned_send_data_to_root.push_back(iproc);
24890 
24891  // Get the number of nodes shared between the processors
24892  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24893 
24894  // Send the number of nodes shared with the iproc processor
24895  package_unsigned_send_data_to_root.push_back(n_nodes);
24896 
24897  // Loop over the nodes
24898  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24899  {
24900  // Get the node
24901  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24902 
24903  // Get the alias info.
24904  Vector<Vector<unsigned>> alias_node_info = node_alias[shd_node_pt];
24905 
24906  // Get the number of alias for the node
24907  const unsigned n_alias = alias_node_info.size();
24908 
24909  // Send the number of alias assigned to the node
24910  package_unsigned_send_data_to_root.push_back(n_alias);
24911 
24912  // Loop over the alias to include them in the package
24913  for (unsigned i = 0; i < n_alias; i++)
24914  {
24915  // Send the alias info.
24916  // The current processor
24917  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24918  // The prociesso with which is shared
24919  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24920  // The index of the node
24921  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24922  } // for (i < n_alias)
24923 
24924  } // for (ishd < n_nodes)
24925 
24926  // Now send the adjacency matrix
24927  for (unsigned i = 0; i < n_nodes; i++)
24928  {
24929  for (unsigned j = 0; j < n_nodes; j++)
24930  {
24931  // Package the adjacency matrix
24932  package_unsigned_send_data_to_root.push_back(
24933  local_adjacency_matrix[iproc][i][j]);
24934 
24935  } // for (j < n_nodes)
24936 
24937  } // for (i < n_nodes)
24938 
24939  } // for (iproc < nproc)
24940 
24941  // Define the root processor
24942  const unsigned root_processor = 0;
24943 
24944  // Get the communicator of the mesh
24945  OomphCommunicator* comm_pt = this->communicator_pt();
24946 
24947  // Number of data send. from this processor to root processor
24948  unsigned n_unsigned_data_send_to_root =
24949  package_unsigned_send_data_to_root.size();
24950 
24951  // Store the number of data to receive from each processor in root
24952  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24953 
24954  // Send the number of data that each processor will send to root
24955  // Gather the info. in the "root_processor"
24956  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24957  // each processor
24958  1, // Total number of data to send from each processor
24959  MPI_UNSIGNED,
24960  &n_unsigned_data_received_in_root[0], // Container where
24961  // to receive the
24962  // info. from all
24963  // the processors
24964  1, // Number of data to receive from each processor
24965  MPI_UNSIGNED,
24966  root_processor, // The processor that receives all the
24967  // info.
24968  comm_pt->mpi_comm());
24969 
24970  // Compute the total number of data to receive from all processors
24971  unsigned n_unsigned_total_data_receive_in_root = 0;
24972  for (unsigned iproc = 0; iproc < nproc; iproc++)
24973  {
24974  // Add the number of data to receive from each processor
24975  n_unsigned_total_data_receive_in_root +=
24976  n_unsigned_data_received_in_root[iproc];
24977  }
24978 
24979  // Compute the offsets from each processor
24980  Vector<int> root_unsigned_offsets_receive(nproc, 0);
24981  root_unsigned_offsets_receive[0] = 0;
24982  for (unsigned iproc = 1; iproc < nproc; iproc++)
24983  {
24984  // Compute the offset to store the values received from each
24985  // processor
24986  root_unsigned_offsets_receive[iproc] =
24987  root_unsigned_offsets_receive[iproc - 1] +
24988  n_unsigned_data_received_in_root[iproc - 1];
24989  }
24990 
24991  // Create at least one entry so we don't get a seg fault below
24992  if (package_unsigned_send_data_to_root.size() == 0)
24993  {
24994  package_unsigned_send_data_to_root.resize(1);
24995  }
24996 
24997  // Vector where to receive the data sent from each processor
24998  Vector<unsigned> package_unsigned_data_received_root(
24999  n_unsigned_total_data_receive_in_root);
25000  if (my_rank != root_processor)
25001  {
25002  // Create at least one entry so we don't get a seg fault below
25003  if (package_unsigned_data_received_root.size() == 0)
25004  {
25005  package_unsigned_data_received_root.resize(1);
25006  }
25007  } // if (my_rank!=root_processor)
25008 
25009  // Gather the info. from all processors
25010  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
25011  // to send
25012  // info. from
25013  // each
25014  // processor
25015  n_unsigned_data_send_to_root, // Total number of data to
25016  // send from each
25017  // processor
25018  MPI_UNSIGNED,
25019  &package_unsigned_data_received_root[0], // Container
25020  // where to
25021  // receive the
25022  // info. from
25023  // all the
25024  // processors
25025  &n_unsigned_data_received_in_root[0], // Number of data
25026  // to receive from
25027  // each processor
25028  &root_unsigned_offsets_receive[0], // The offset to
25029  // store the
25030  // info. from each
25031  // processor
25032  MPI_UNSIGNED,
25033  root_processor, // The processor that receives all the
25034  // info.
25035  comm_pt->mpi_comm());
25036 
25037  // Store the info. to be sent by root to other processors
25038  Vector<unsigned> package_unsigned_data_sent_from_root;
25039  // Total data sent to each processor from root
25040  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
25041 
25042  // The root processor now has all the info. regarding the shared
25043  // nodes and the adjacency matrix of each pair of processors
25044  if (my_rank == root_processor)
25045  {
25046  // Decode the info. received from all processors
25047  // Counter to decode the info.
25048  unsigned decode_counter = 0;
25049 
25050  // Store the local alias of the nodes in each processor
25051  // [x][][][][] iproc
25052  // [][x][][][] jproc
25053  // [][][x][][] inode
25054  // [][][][x][] ialias
25055  // [][][][][x] alias_data
25056  Vector<Vector<Vector<Vector<Vector<unsigned>>>>> local_node_alias(nproc);
25057  // Store the local adjacency matrix of each processor
25058  Vector<Vector<Vector<Vector<unsigned>>>> local_adjacency_matrix(nproc);
25059 
25060  // Loop over all the processors
25061  for (unsigned iproc = 0; iproc < nproc; iproc++)
25062  {
25063  local_node_alias[iproc].resize(nproc);
25064 
25065  // Resize the local adjacency matrix to store the info. sent
25066  // from all processors
25067  local_adjacency_matrix[iproc].resize(nproc);
25068 
25069  if (n_unsigned_data_received_in_root[iproc] > 0)
25070  {
25071  // Loop over all the processors to decode the info. received
25072  // from each one
25073  for (unsigned jproc = 0; jproc < nproc; jproc++)
25074  {
25075  // Read the processor number to which the info. correspond
25076  const unsigned read_jproc =
25077  package_unsigned_data_received_root[decode_counter++];
25078 
25079  // The read processor must be the same as the jproc, if that
25080  // is not the case then there is a synchronisation issue
25081  if (read_jproc != jproc)
25082  {
25083  std::ostringstream error_stream;
25084  error_stream
25085  << "The read processor is different from the jproc, this is\n"
25086  << "a synchronisation issue. The data are not read in the\n"
25087  << "sameorder as the were packaged\n"
25088  << "Read processor: (" << read_jproc << ")\n"
25089  << "Current jproc: (" << jproc << ")\n\n";
25090  throw OomphLibError(
25091  error_stream.str(),
25092  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25093  OOMPH_EXCEPTION_LOCATION);
25094  }
25095 
25096  // Read the number of nodes in the shared boundaries between
25097  // iproc and jproc
25098  const unsigned read_n_shd_nodes_iproc_jproc =
25099  package_unsigned_data_received_root[decode_counter++];
25100 
25101  // Resize the container
25102  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
25103 
25104  // Loop over the number of nodes shared between iproc and
25105  // jproc
25106  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
25107  {
25108  // Read the number of alias of the current ishd node
25109  const unsigned read_n_alias_node_iproc_jproc =
25110  package_unsigned_data_received_root[decode_counter++];
25111 
25112  // Resize the container
25113  local_node_alias[iproc][jproc][ishd].resize(
25114  read_n_alias_node_iproc_jproc);
25115 
25116  for (unsigned ialias = 0; ialias < read_n_alias_node_iproc_jproc;
25117  ialias++)
25118  {
25119  // Resize the container, we know there are three data to
25120  // define the alias of a node
25121  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
25122 
25123  // The 1st processor with which is shared
25124  local_node_alias[iproc][jproc][ishd][ialias][0] =
25125  package_unsigned_data_received_root[decode_counter++];
25126 
25127  // The 2nd processor with which is shared
25128  local_node_alias[iproc][jproc][ishd][ialias][1] =
25129  package_unsigned_data_received_root[decode_counter++];
25130 
25131  // The index of the node in the interaction iproc-jproc
25132  local_node_alias[iproc][jproc][ishd][ialias][2] =
25133  package_unsigned_data_received_root[decode_counter++];
25134 
25135  } // for (ialias < read_n_alias_node_iproc_jproc)
25136 
25137  } // for (ishd < read_n_shd_nodes_iproc_jproc)
25138 
25139  // Resize the local adjacency matrix
25140  local_adjacency_matrix[iproc][jproc].resize(
25141  read_n_shd_nodes_iproc_jproc);
25142  // Read the adjacency matrix sent to root processor
25143  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
25144  {
25145  // Resize the local adjacency matrix
25146  local_adjacency_matrix[iproc][jproc][i].resize(
25147  read_n_shd_nodes_iproc_jproc);
25148  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
25149  {
25150  // Read the adjacency matrix entry
25151  local_adjacency_matrix[iproc][jproc][i][j] =
25152  package_unsigned_data_received_root[decode_counter++];
25153  } // for (j < read_n_shd_nodes_iproc_jproc)
25154 
25155  } // for (i < read_n_shd_nodes_iproc_jproc)
25156 
25157  } // for (jproc < nproc)
25158 
25159  } // for (iproc < nproc)
25160 
25161  } // for (iproc < nproc)
25162 
25163 #ifdef PARANOID
25164  if (decode_counter != n_unsigned_total_data_receive_in_root)
25165  {
25166  std::ostringstream error_stream;
25167  error_stream
25168  << "The number of data decoded in root received from others\n"
25169  << "processors is different from the total number of data received\n"
25170  << "Data decoded: (" << decode_counter << ")\n"
25171  << "Data received: (" << n_unsigned_total_data_receive_in_root
25172  << ")\n\n"
25173  << "This is a synchronisation issue so you are probably sending\n"
25174  << "more or less info. than the one that is being decoded\n\n";
25175  throw OomphLibError(
25176  error_stream.str(),
25177  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25178  OOMPH_EXCEPTION_LOCATION);
25179  }
25180 #endif
25181 
25182  // Assign a unique id to the nodes (uses the alias information to
25183  // identify the repetition of a node in other processors). The
25184  // global node id is given by the position (index) in the global
25185  // node alias
25186 
25187  // Keep track of those alias already assigned a unique id
25188  std::map<Vector<unsigned>, bool> alias_done;
25189 
25190  // Store all the alias associated to each node
25191  Vector<Vector<Vector<unsigned>>> global_node_alias;
25192 
25193  // Loop over all the processors
25194  for (unsigned iproc = 0; iproc < nproc; iproc++)
25195  {
25196  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25197  {
25198  // Read the number of nodes shared between the processors
25199  const unsigned n_shd_nodes_iproc_jproc =
25200  local_node_alias[iproc][jproc].size();
25201 #ifdef PARANOID
25202  // Read the number of nodes shared in the other direction
25203  const unsigned n_shd_nodes_jproc_iproc =
25204  local_node_alias[jproc][iproc].size();
25205 
25206  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
25207  {
25208  std::ostringstream error_stream;
25209  error_stream
25210  << "The number of nodes shared between iproc and jproc is\n"
25211  << "different from the number of nodes shared between jproc\n"
25212  << "and iproc\n"
25213  << "Nodes shared between processor (" << iproc << ") and "
25214  << "processor (" << jproc << "): (" << n_shd_nodes_iproc_jproc
25215  << ")\n"
25216  << "Nodes shared between processor (" << jproc << ") and "
25217  << "processor (" << iproc << "): (" << n_shd_nodes_jproc_iproc
25218  << ")\n\n";
25219  throw OomphLibError(
25220  error_stream.str(),
25221  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25222  OOMPH_EXCEPTION_LOCATION);
25223  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
25224 #endif
25225 
25226  // Loop over the nodes shared between the processors
25227  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
25228  {
25229  // Get the number of alias associated to the node on each
25230  // processor
25231  const unsigned n_alias_iproc_jproc =
25232  local_node_alias[iproc][jproc][ishd].size();
25233  const unsigned n_alias_jproc_iproc =
25234  local_node_alias[jproc][iproc][ishd].size();
25235 
25236  // Store all the found alias to the node
25237  Vector<Vector<unsigned>> node_alias;
25238 
25239  // Flag to indicate if a new alias has been added
25240  bool new_alias_added = false;
25241 
25242  // Start by adding the "direct" alias of the node
25243  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
25244  {
25245  // Get the alias of the node
25246  Vector<unsigned> current_alias =
25247  local_node_alias[iproc][jproc][ishd][ialias];
25248  // Check if already done
25249  if (!alias_done[current_alias])
25250  {
25251  // Add the alias of the node
25252  node_alias.push_back(current_alias);
25253  // Set the flag to indicate a new alias has been added
25254  new_alias_added = true;
25255  // Mark the alias as done
25256  alias_done[current_alias] = true;
25257  } // if (!alias_done[i_alias])
25258 
25259  } // for (ialias < n_alias_iproc_jproc)
25260 
25261  // Start by adding the "direct" alias of the node
25262  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25263  {
25264  // Get the alias of the node
25265  Vector<unsigned> current_alias =
25266  local_node_alias[jproc][iproc][ishd][ialias];
25267 
25268  // Check if already done
25269  if (!alias_done[current_alias])
25270  {
25271  // Add the alias of the node
25272  node_alias.push_back(current_alias);
25273  // Set the flag to indicate a new alias has been added
25274  new_alias_added = true;
25275  // Mark the alias as done
25276  alias_done[current_alias] = true;
25277  } // if (!alias_done[i_alias])
25278 
25279  } // for (ialias < n_alias_jproc_iproc)
25280 
25281  unsigned counter_alias = 0;
25282  // Visit the alias of the node and add any new found
25283  // alias, end until all its alias have been included
25284 
25285  unsigned n_current_alias = node_alias.size();
25286  while (new_alias_added || counter_alias < n_current_alias)
25287  // while(new_alias_added) // we need to check all the alias,
25288  // including those added during the process
25289  {
25290  new_alias_added = false;
25291  // Store the current visited alias
25292  Vector<unsigned> current_alias = node_alias[counter_alias];
25293 
25294  // Get the alias associated with the current alias
25295  Vector<Vector<unsigned>> alias_of_current_alias =
25296  local_node_alias[current_alias[0]][current_alias[1]]
25297  [current_alias[2]];
25298 
25299  // Get all the alias associated with the alias of the
25300  // current alias
25301  const unsigned n_alias = alias_of_current_alias.size();
25302 
25303  // Loop over the new alias and check if require to add
25304  // them
25305  for (unsigned k = 0; k < n_alias; k++)
25306  {
25307  // Get the alias of the node
25308  Vector<unsigned> add_alias = alias_of_current_alias[k];
25309 
25310  // Check if already done
25311  if (!alias_done[add_alias])
25312  {
25313  // Add the alias of the node
25314  node_alias.push_back(add_alias);
25315  // Set the flag to indicate a new alias has been
25316  // added
25317  new_alias_added = true;
25318  // Mark the alias ad done
25319  alias_done[add_alias] = true;
25320  } // if (!alias_done[i_alias])
25321 
25322  } // for (k < n_alias)
25323 
25324  // Get the alias associated with the current alias (in the
25325  // other direction)
25326  Vector<Vector<unsigned>> alias_of_current_alias2 =
25327  local_node_alias[current_alias[1]][current_alias[0]]
25328  [current_alias[2]];
25329 
25330  // Get all the alias associated with the current alias
25331  // (in the other direction)
25332  const unsigned n_alias2 = alias_of_current_alias2.size();
25333 
25334  // Loop over the new alias and check if require to add
25335  // them
25336  for (unsigned k = 0; k < n_alias2; k++)
25337  {
25338  // Get the alias of the node
25339  Vector<unsigned> add_alias = alias_of_current_alias2[k];
25340 
25341  // Check if already done
25342  if (!alias_done[add_alias])
25343  {
25344  // Add the alias of the node
25345  node_alias.push_back(add_alias);
25346  // Set the flag to indicate a new alias has been
25347  // added
25348  new_alias_added = true;
25349  // Mark the alias ad done
25350  alias_done[add_alias] = true;
25351  } // if (!alias_done[i_alias])
25352 
25353  } // for (k < n_alias)
25354 
25355  // Go for the next alias
25356  counter_alias++;
25357 
25358  // Update the number of alias so that the while stops when
25359  // all the alias have been visited and no new alias was
25360  // added
25361  n_current_alias = node_alias.size();
25362 
25363  } // while(new_alias_added || counter_alias < n_current_alias)
25364 
25365  // If the node has not been previously added, then include
25366  // all its alias
25367  if (node_alias.size() > 0)
25368  {
25369  // Add all the found alias of the node to the global alias
25370  // storage
25371  global_node_alias.push_back(node_alias);
25372  }
25373 
25374  } // for (ishd < n_shd_nodes_iproc_jproc)
25375 
25376  } // for (jproc < nproc)
25377 
25378  } // for (iproc < nproc)
25379 
25380  // We now have the global number of nodes, each with its own id
25381  // (the index in the global_node_alias vector)
25382 
25383  // Get the number of global shared nodes
25384  const unsigned n_global_shared_nodes = global_node_alias.size();
25385 
25386  // Create matrix from local to global shared node id
25387  Vector<Vector<Vector<int>>> local_to_global_shared_node(nproc);
25388 
25389  // Loop over all the processors to resize
25390  for (unsigned iproc = 0; iproc < nproc; iproc++)
25391  {
25392  // Resize the map matrix
25393  local_to_global_shared_node[iproc].resize(nproc);
25394  } // for (iproc < nproc)
25395 
25396  // Loop over all the processors to resize (the third direction,
25397  // required if we want to loop over the half of the matrix only)
25398  for (unsigned iproc = 0; iproc < nproc; iproc++)
25399  {
25400  // Loop over the half of the matrix to resize
25401  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25402  {
25403  // Read the number of nodes shared between the processors
25404  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25405 
25406  // Resize the map matrix
25407  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes, -1);
25408 
25409  // ... and resize the other half map matrix
25410  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes, -1);
25411 
25412  } // for (jproc < nproc)
25413 
25414  } // for (iproc < nproc)
25415 
25416  // Fill the matrix for mapping from local to global node id
25417 
25418  // Loop over the global nodes, and for each alias assign the
25419  // corresponding global node id
25420  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25421  {
25422  // Get the number of alias associated to the current global node
25423  const unsigned n_alias_global_node = global_node_alias[k].size();
25424  // Loop over the alias and assign the global node id
25425  for (unsigned l = 0; l < n_alias_global_node; l++)
25426  {
25427  // Get the 1st processor
25428  const unsigned iproc = global_node_alias[k][l][0];
25429  // Get the 2nd processor
25430  const unsigned jproc = global_node_alias[k][l][1];
25431  // Get the node number
25432  const unsigned ishd = global_node_alias[k][l][2];
25433  // Assign the global node id
25434  local_to_global_shared_node[iproc][jproc][ishd] = k;
25435 
25436  } // for (l < n_alias_global_node)
25437 
25438  } // for (k < n_global_shared_nodes)
25439 
25440  // Create the global adjacency matrix
25441  Vector<Vector<unsigned>> global_adjacency_matrix(n_global_shared_nodes);
25442  // Resize the global adjacency matrix
25443  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25444  {
25445  // Resize
25446  global_adjacency_matrix[k].resize(n_global_shared_nodes, 0);
25447  } // for (k < n_global_shared_nodes)
25448 
25449  // Add the entries to the global adjacency matrix and compute the
25450  // degree of each node
25451 
25452  // Store the degree of the global nodes
25453  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25454 
25455  // Loop over the processors
25456  for (unsigned iproc = 0; iproc < nproc; iproc++)
25457  {
25458  // Loop over the half of the matrix to resize
25459  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25460  {
25461  // Get the number of nodes shared between the processors
25462  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25463 
25464  // Search for entries in the local adjacency matrix that set a
25465  // connection among the nodes
25466 
25467  // Loop over the shared nodes in the current pair of
25468  // processors
25469  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25470  {
25471  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25472  {
25473  // Are the nodes associated
25474  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25475  {
25476  // Get the global nodes id
25477 
25478  // Get the "left-node" global id
25479  const int global_shd_node_left =
25480  local_to_global_shared_node[iproc][jproc][ishd];
25481 
25482  // Get the "right-node" global id
25483  const int global_shd_node_right =
25484  local_to_global_shared_node[iproc][jproc][jshd];
25485 
25486 #ifdef PARANOID
25487  // Check if the local nodes have a global node
25488  // associated
25489  if (global_shd_node_left == -1)
25490  {
25491  std::ostringstream error_stream;
25492  error_stream
25493  << "The local node in processors iproc and jproc has no\n"
25494  << "global node assigned\n"
25495  << "iproc processor: (" << iproc << ")\n"
25496  << "jproc processor: (" << jproc << ")\n"
25497  << "Local node: (" << ishd << ")\n\n";
25498  throw OomphLibError(error_stream.str(),
25499  "RefineableTriangleMesh::compute_shared_"
25500  "node_degree_helper()",
25501  OOMPH_EXCEPTION_LOCATION);
25502  }
25503 
25504  // Check if the local nodes have a global node
25505  // associated
25506  if (global_shd_node_right == -1)
25507  {
25508  std::ostringstream error_stream;
25509  error_stream
25510  << "The local node in processors iproc and jproc has no\n"
25511  << "global node assigned\n"
25512  << "iproc processor: (" << iproc << ")\n"
25513  << "jproc processor: (" << jproc << ")\n"
25514  << "Local node: (" << jshd << ")\n\n";
25515  throw OomphLibError(error_stream.str(),
25516  "RefineableTriangleMesh::compute_shared_"
25517  "node_degree_helper()",
25518  OOMPH_EXCEPTION_LOCATION);
25519  }
25520 #endif
25521  // Get the unsigned version of the indexes
25522  const unsigned uleft =
25523  static_cast<unsigned>(global_shd_node_left);
25524  const unsigned uright =
25525  static_cast<unsigned>(global_shd_node_right);
25526 
25527  // Add the entry in the global adjacency matrix
25528  global_adjacency_matrix[uleft][uright]++;
25529 
25530  // ... and in the other direction too
25531  global_adjacency_matrix[uright][uleft]++;
25532 
25533  // Add on to the degree of the left node
25534  global_node_degree[uleft]++;
25535 
25536  // Add on to the degree of the right node
25537  global_node_degree[uright]++;
25538 
25539  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25540 
25541  } // // for (jshd < n_shd_nodes)
25542 
25543  } // for (ishd < n_shd_nodes)
25544 
25545  } // for (jproc < nproc)
25546 
25547  } // for (iproc < nproc)
25548 
25549  // Assign the global degree to the shared nodes between each pair
25550  // of processors
25551  Vector<Vector<Vector<unsigned>>> root_local_node_degree(nproc);
25552  // Resize the container
25553  for (unsigned iproc = 0; iproc < nproc; iproc++)
25554  {
25555  root_local_node_degree[iproc].resize(nproc);
25556  }
25557 
25558  // Loop over the processors and visited their shared nodes
25559  for (unsigned iproc = 0; iproc < nproc; iproc++)
25560  {
25561  // Only visit the half of the data
25562  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25563  {
25564  // Get the number of shared nodes between this pair of
25565  // processors (iproc, jproc)
25566  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25567 
25568  // Resize the container to store the local degree of the nodes
25569  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25570  // ... and in the other way too
25571  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25572 
25573  // Loop over the number of nodes shared between the pair of
25574  // processors
25575  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25576  {
25577  // Get the global node id for the current shared node
25578  const int global_shd_node_id =
25579  local_to_global_shared_node[iproc][jproc][ishd];
25580 
25581 #ifdef PARANOID
25582  // Check if the local nodes have a global node associated
25583  if (global_shd_node_id == -1)
25584  {
25585  std::ostringstream error_stream;
25586  error_stream
25587  << "The local node in processors iproc and jproc has no\n"
25588  << "global node assigned\n"
25589  << "iproc processor: (" << iproc << ")\n"
25590  << "jproc processor: (" << jproc << ")\n"
25591  << "Local node: (" << ishd << ")\n\n";
25592  throw OomphLibError(
25593  error_stream.str(),
25594  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25595  OOMPH_EXCEPTION_LOCATION);
25596  }
25597 #endif
25598 
25599  // Get the unsigned version of the global index
25600  const unsigned uglobal_shd_node_id =
25601  static_cast<unsigned>(global_shd_node_id);
25602 
25603  // Get the degree of the node
25604  const unsigned node_degree =
25605  global_node_degree[uglobal_shd_node_id];
25606 
25607  // Set the degree in the container for the degree of the
25608  // nodes in the local interaction between processors
25609  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25610  // ... and in the other way too
25611  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25612 
25613  } // for (ishd < n_shd_nodes)
25614 
25615  } // for (jproc < nproc)
25616 
25617  } // for (iproc < nproc)
25618 
25619  // Clear the container where the info. will be sent back to each
25620  // processor
25621  package_unsigned_data_sent_from_root.clear();
25622 
25623  // Prepare the data to sent it back to each processor (encode the
25624  // info. to sent to all processors)
25625  for (unsigned iproc = 0; iproc < nproc; iproc++)
25626  {
25627  // Count the number of data sent to iproc processor
25628  unsigned count_n_data_sent_to_iproc = 0;
25629  for (unsigned jproc = 0; jproc < nproc; jproc++)
25630  {
25631  // No shared nodes between the same processor
25632  if (iproc != jproc)
25633  {
25634  // Get the number of nodes shared between the processors
25635  const unsigned n_shd_nodes =
25636  root_local_node_degree[iproc][jproc].size();
25637 
25638  // Add the number of data sent to iproc processor
25639  count_n_data_sent_to_iproc += n_shd_nodes;
25640 
25641  // Loop over the nodes shared between the pair of processors
25642  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25643  {
25644  package_unsigned_data_sent_from_root.push_back(
25645  root_local_node_degree[iproc][jproc][ishd]);
25646  } // for (ishd < n_shd_nodes)
25647 
25648  } // if (iproc != jproc)
25649 
25650  } // for (jproc < nproc)
25651 
25652  // Set the number of data sent to iproc processor
25653  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25654 
25655  } // for (iproc < nproc)
25656 
25657  } // if (my_rank == root_processor)
25658 
25659  // Total data received from root to this processor
25660  int n_unsigned_data_received_from_root = 0;
25661 
25662  // Get the number of data that each processor receives from root
25663  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25664  // root to each
25665  // processor
25666  1, // The number of data sent from root to each
25667  // processor
25668  MPI_UNSIGNED,
25669  &n_unsigned_data_received_from_root, // Store the
25670  // info. received
25671  // from root
25672  1, // The number of data received from root
25673  MPI_UNSIGNED,
25674  root_processor, // The processor that sends the
25675  // info.
25676  comm_pt->mpi_comm());
25677 
25678  // Receive the info. sent by root
25679  Vector<unsigned> package_unsigned_data_received_from_root(
25680  n_unsigned_data_received_from_root);
25681 
25682  // Compute the offsets to each processor
25683  Vector<int> root_unsigned_offsets_sent(nproc, 0);
25684  root_unsigned_offsets_sent[0] = 0;
25685  for (unsigned iproc = 1; iproc < nproc; iproc++)
25686  {
25687  // Compute the offset to send the values to each processor
25688  root_unsigned_offsets_sent[iproc] =
25689  root_unsigned_offsets_sent[iproc - 1] +
25690  n_unsigned_data_sent_from_root[iproc - 1];
25691  }
25692 
25693  if (my_rank != root_processor)
25694  {
25695  // Create at least one entry so we don't get a seg fault below
25696  if (package_unsigned_data_sent_from_root.size() == 0)
25697  {
25698  package_unsigned_data_sent_from_root.resize(1);
25699  }
25700  } // if (my_rank!=root_processor)
25701 
25702  // Create at least one entry so we don't get a seg fault below
25703  if (package_unsigned_data_received_from_root.size() == 0)
25704  {
25705  package_unsigned_data_received_from_root.resize(1);
25706  }
25707 
25708  // Get the data from root
25709  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25710  // info. sent
25711  // from root
25712  // to others
25713  // processors
25714  &n_unsigned_data_sent_from_root[0], // The number of
25715  // data sent from
25716  // root to others
25717  // processors
25718  &root_unsigned_offsets_sent[0], // The offsets to each
25719  // processors
25720  MPI_UNSIGNED,
25721  &package_unsigned_data_received_from_root[0], // The
25722  // storage
25723  // in the
25724  // processor
25725  // that
25726  // receives
25727  // the
25728  // info.
25729  n_unsigned_data_received_from_root, // The number of
25730  // data that the
25731  // current
25732  // processor
25733  // receives from
25734  // root
25735  MPI_UNSIGNED,
25736  root_processor, // The root processors
25737  comm_pt->mpi_comm());
25738 
25739  // Decode the info.
25740 
25741  // Keep track of the already nodes done
25742  std::map<Node*, bool> node_done;
25743 
25744  // Read the global degree assigned to the shared nodes between the
25745  // current processors and the other processors
25746  int decode_counter = 0;
25747  // Store the global degree of the local nodes
25748  Vector<Vector<unsigned>> local_node_degree(nproc);
25749  // Loop over the processors
25750  for (unsigned iproc = 0; iproc < nproc; iproc++)
25751  {
25752  // There are no shared nodes with the current processor itself
25753  if (iproc != my_rank)
25754  {
25755  // Get the number of nodes shared with the iproc processor
25756  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25757 
25758  // Read the global degree of the node
25759  package_unsigned_send_data_to_root.push_back(n_nodes);
25760 
25761  // Loop over the nodes
25762  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25763  {
25764  // Get the node degree assigned to the ishd node in between
25765  // the interaction of the iproc and the current processor
25766  const unsigned node_degree =
25767  package_unsigned_data_received_from_root[decode_counter++];
25768 
25769  // Get the node
25770  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
25771 
25772  // Has the node been assigned a global degree
25773  if (!node_done[shd_node_pt])
25774  {
25775  // Assign the global degree to the node
25776  global_node_degree[shd_node_pt] = node_degree;
25777  // Mark the node as done
25778  node_done[shd_node_pt] = true;
25779  }
25780 #ifdef PARANOID
25781  else
25782  {
25783  // The node has been already done, check that the node
25784  // degree is the same as the already assigned
25785  if (global_node_degree[shd_node_pt] != node_degree)
25786  {
25787  std::ostringstream error_stream;
25788  error_stream
25789  << "The local node has already assigned a global degree,\n"
25790  << "however, a different degree for the same node has been\n"
25791  << "read from the data sent from root processor\n"
25792  << "iproc processor: (" << iproc << ")\n"
25793  << "Local node: (" << ishd << ")\n"
25794  << "---------------------------------------------------------\n"
25795  << "Already assigned degree: ("
25796  << global_node_degree[shd_node_pt] << ")\n"
25797  << "New found degree: (" << node_degree << ")\n"
25798  << "---------------------------------------------------------\n"
25799  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25800  << shd_node_pt->x(1) << ")\n\n";
25801  throw OomphLibError(
25802  error_stream.str(),
25803  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25804  OOMPH_EXCEPTION_LOCATION);
25805  }
25806 
25807  } // else if (!node_done[shd_node_pt])
25808 #endif // #ifdef PARANOID
25809 
25810  } // for (ishd < n_nodes)
25811 
25812  } // if (iproc != my_rank)
25813 
25814  } // for (iproc < nproc)
25815 
25816 #ifdef PARANOID
25817  // Ensure that all the info. sent from root processor has been read
25818  if (decode_counter != n_unsigned_data_received_from_root)
25819  {
25820  std::ostringstream error_stream;
25821  error_stream
25822  << "The number of data decoded received from root processor is\n"
25823  << "different from the total number of data received from the root\n"
25824  << "processor\n"
25825  << "Data decoded: (" << decode_counter << ")\n"
25826  << "Data received: (" << n_unsigned_data_received_from_root << ")\n\n"
25827  << "This is a synchronisation issue so you are probably sending\n"
25828  << "more or less info. than the one that is being decoded\n\n";
25829  throw OomphLibError(
25830  error_stream.str(),
25831  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25832  OOMPH_EXCEPTION_LOCATION);
25833  }
25834 #endif
25835  }
25836 
25837  //======================================================================
25838  // Sort the nodes on the new shared boundaries (after load balancing),
25839  // computes the alias of the nodes and creates the adjacency matrix
25840  // that represent the graph created by the shared edges between each
25841  // pair of processors
25842  // ======================================================================
25843  template<class ELEMENT>
25846  Vector<Vector<FiniteElement*>>& unsorted_face_ele_pt,
25847  Vector<Vector<Node*>>& tmp_sorted_shared_node_pt,
25848  std::map<Node*, Vector<Vector<unsigned>>>& node_alias,
25849  Vector<Vector<Vector<unsigned>>>& adjacency_matrix)
25850  {
25851  // Get the number of processors and the rank
25852  const unsigned nproc = this->communicator_pt()->nproc();
25853  const unsigned my_rank = this->communicator_pt()->my_rank();
25854 
25855  // Assign a unique id to each node shared between each pair of
25856  // processors, in this case the current processor and the iproc
25857 
25858  // ... also compute the alias of each node (processor and index of
25859  // the node in all processors where it appears)
25860 
25861  // Clear the alias info
25862  node_alias.clear();
25863 
25864  // Temporary storage for the index of the nodes
25865  Vector<std::map<Node*, unsigned>> tmp_node_index(nproc);
25866 
25867  // Loop over the processors
25868  for (unsigned iproc = 0; iproc < nproc; iproc++)
25869  {
25870  // There is no shared elements between the same processor
25871  if (iproc != my_rank)
25872  {
25873  // Map to mark those nodes already visited
25874  std::map<Node*, bool> done_node;
25875 
25876  // A map is used to sort the nodes using their coordinates as
25877  // the key of the map
25878  // std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25879  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25880 
25881  // Get the number of unsorted face elements
25882  const unsigned n_unsorted_face_ele = unsorted_face_ele_pt[iproc].size();
25883 
25884  // Loop over the unsorted elements
25885  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25886  {
25887  // Get a root element
25888  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25889  // Get the left node of the face element
25890  Node* left_node_pt = face_ele_pt->node_pt(0);
25891 
25892  // Check if the node has been already sorted in the
25893  // interaction between the current processor and iproc
25894  // processor
25895  if (!done_node[left_node_pt])
25896  {
25897  std::pair<double, double> vertex =
25898  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25899  sorted_nodes_pt[vertex] = left_node_pt;
25900  // Mark the node as done
25901  done_node[left_node_pt] = true;
25902  }
25903 
25904  // Get the number of nodes of the face element
25905  const unsigned n_nodes = face_ele_pt->nnode();
25906  // Get the right node of the face element
25907  Node* right_node_pt = face_ele_pt->node_pt(n_nodes - 1);
25908 
25909  // Check if the node has been already sorted in the
25910  // interaction between the current processor and iproc
25911  // processor
25912  if (!done_node[right_node_pt])
25913  {
25914  std::pair<double, double> vertex =
25915  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25916  sorted_nodes_pt[vertex] = right_node_pt;
25917  // Mark the node as done
25918  done_node[right_node_pt] = true;
25919  }
25920 
25921  } // for (e < nunsorted_face_ele)
25922 
25923  // The nodes are already sorted, we need to return them in the
25924  // proper container
25925 
25926  // The counter to enumerate the nodes
25927  unsigned counter = 0;
25928 
25929  // Go through the map container which already have the nodes
25930  // sorted they have the same sorting on all processors
25931  for (std::map<std::pair<double, double>, Node*>::iterator it =
25932  sorted_nodes_pt.begin();
25933  it != sorted_nodes_pt.end();
25934  it++)
25935  {
25936  // Get the node
25937  Node* node_pt = (*it).second;
25938  // Store the node at the corresponding index
25939  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25940 
25941  // Create the temporary access to the node index
25942  tmp_node_index[iproc][node_pt] = counter;
25943 
25944  // Fill the info. for the node alias
25945  Vector<unsigned> alias(3);
25946  // The current processor
25947  alias[0] = my_rank;
25948  // The processor with which is shared
25949  alias[1] = iproc;
25950  // The index with that processor
25951  alias[2] = counter++;
25952 
25953  // Store the info. of the alias
25954  node_alias[node_pt].push_back(alias);
25955 
25956  } // Loop map
25957 
25958  } // if (iproc != my_rank)
25959 
25960  } // for (iproc < nproc)
25961 
25962  // Loop over the processors to resize and initialize the adjacency
25963  // matrix
25964  for (unsigned iproc = 0; iproc < nproc; iproc++)
25965  {
25966  // Get the number of nodes shared with iproc
25967  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25968  // Resize the adjacency matrix
25969  adjacency_matrix[iproc].resize(n_shd_nodes);
25970  for (unsigned i = 0; i < n_shd_nodes; i++)
25971  {
25972  // Resize the adjacency matrix
25973  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25974 
25975  // Initialize the
25976  for (unsigned j = 0; j < n_shd_nodes; j++)
25977  {
25978  adjacency_matrix[iproc][i][j] = 0;
25979  } // for (j < n_shd_nodes)
25980 
25981  } // for (i < n_shd_nodes)
25982 
25983  } // for (iproc < nproc)
25984 
25985  // Loop over the processors to fill the adjacency matrix
25986  for (unsigned iproc = 0; iproc < nproc; iproc++)
25987  {
25988  // There is no shared elements between the same processor
25989  if (iproc != my_rank)
25990  {
25991  // Get the number of unsorted face elements
25992  const unsigned n_unsorted_face_ele = unsorted_face_ele_pt[iproc].size();
25993 
25994  // Loop over the unsorted elements
25995  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25996  {
25997  // Get a root element
25998  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25999  // Get the left node of the face element
26000  Node* left_node_pt = face_ele_pt->node_pt(0);
26001 
26002  // Get the number of nodes of the face element
26003  const unsigned n_nodes = face_ele_pt->nnode();
26004  // Get the right node of the face element
26005  Node* right_node_pt = face_ele_pt->node_pt(n_nodes - 1);
26006 
26007  // Get the index of each of the nodes
26008  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
26009  const unsigned right_node_index =
26010  tmp_node_index[iproc][right_node_pt];
26011 
26012  // Add an entry to the adjacency matrix to indicate the
26013  // association of left and right node
26014  adjacency_matrix[iproc][left_node_index][right_node_index]++;
26015  // ... both directions
26016  adjacency_matrix[iproc][right_node_index][left_node_index]++;
26017 
26018  } // for (e < n_unsorted_face_ele)
26019 
26020  } // if (iproc != my_rank)
26021 
26022  } // for (iproc < nproc)
26023  }
26024 
26025  //======================================================================
26026  /// \short Get the nodes on the shared boundary (b), these are stored
26027  /// in the segment they belong
26028  //======================================================================
26029  template<class ELEMENT>
26032  const unsigned& shd_bnd_id, Vector<Vector<Node*>>& tmp_segment_nodes)
26033  {
26034  // Clear the data structure were to return the nodes
26035  tmp_segment_nodes.clear();
26036 
26037  // Get the face elements that created the shared boundary from the
26038  // bulk shared boundary elements
26039 
26040 #ifdef PARANOID
26041  // The temporary storage for the halo face elements
26042  Vector<FiniteElement*> halo_shared_face_ele_pt;
26043 #endif
26044  // The temporary storage for the nonhalo face elements
26045  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
26046 
26047  // Get the number of shared boundary elements associated with the
26048  // current shared boundary
26049  const unsigned nshared_bound_ele =
26050  this->nshared_boundary_element(shd_bnd_id);
26051 
26052  // Loop over the elements in the shared boundary to create the face
26053  // elements
26054  for (unsigned e = 0; e < nshared_bound_ele; e++)
26055  {
26056  // Get the shared boundary element
26057  FiniteElement* bulk_ele_pt =
26058  this->shared_boundary_element_pt(shd_bnd_id, e);
26059 
26060  // Get the face index
26061  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
26062 
26063  // Before adding the new element we need to ensure that the edge
26064  // that this element represents has not been already added
26065  FiniteElement* face_ele_pt =
26066  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
26067 
26068  // Nonhalo element
26069  if (!bulk_ele_pt->is_halo())
26070  {
26071  // Add nonhalo shared face element to the container
26072  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
26073  }
26074 #ifdef PARANOID
26075  else // halo element
26076  {
26077  // Add halo shared face element to the container
26078  halo_shared_face_ele_pt.push_back(face_ele_pt);
26079  }
26080 #endif
26081 
26082  } // for (e < nshared_bound_ele)
26083 
26084  // Mark the face elements already used
26085  std::map<FiniteElement*, bool> shared_face_done;
26086 
26087  // Get the number of nonhalo face elements
26088  const unsigned nnonhalo_face_shared_ele = nonhalo_shared_face_ele_pt.size();
26089 
26090  // If we are in PARANOID mode check that there is one halo element
26091  // for each nonhalo element
26092 #ifdef PARANOID
26093  // Get the number of halo face elements
26094  const unsigned nhalo_face_shared_ele = halo_shared_face_ele_pt.size();
26095 
26096  // The number of nonhalo shared face boundary elements must be the
26097  // half of the total number of shared boundary elements
26098  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
26099  {
26100  std::ostringstream error_message;
26101  error_message
26102  << "The number of shared boundary elements (" << nshared_bound_ele
26103  << ") is not the double\nof the number of unsorted nonhalo shared "
26104  << "face boundary elements (" << nnonhalo_face_shared_ele
26105  << ")\n for the current boundary (" << shd_bnd_id << ")\n\n";
26106  throw OomphLibError(
26107  error_message.str(),
26108  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26109  OOMPH_EXCEPTION_LOCATION);
26110  }
26111 
26112  // The number of halo shared face boundary elements must be the
26113  // half of the total number of shared boundary elements
26114  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
26115  {
26116  std::ostringstream error_message;
26117  error_message
26118  << "The number of shared boundary elements (" << nshared_bound_ele
26119  << ") is not the double\nof the number of unsorted halo shared "
26120  << "face boundary elements (" << nhalo_face_shared_ele
26121  << ")\n for the current boundary (" << shd_bnd_id << ")\n\n";
26122  throw OomphLibError(
26123  error_message.str(),
26124  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26125  OOMPH_EXCEPTION_LOCATION);
26126  }
26127 
26128  // ------------------------------------------------------------------
26129  // Loop over the nonhalo face elements and look for the halo face
26130  // element at the other side of the shared boundary
26131  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26132  {
26133  // Get the inh-th face element
26134  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
26135 
26136  // Get the number of nodes on the face element
26137  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
26138  // Get the first and last node on the element
26139  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
26140  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh - 1);
26141 
26142  // Now find the (halo) face element at the other side of the
26143  // shared boundary
26144  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26145  {
26146  // Get the ih-th face element
26147  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
26148 
26149  // Check that the face element has not been done
26150  if (!shared_face_done[halo_face_ele_pt])
26151  {
26152  // Get the number of nodes on the face element
26153  const unsigned nnodes_h = halo_face_ele_pt->nnode();
26154  // Get the first and last node on the element
26155  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
26156  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h - 1);
26157 
26158  // If the nodes are the same then we have found the (halo)
26159  // face element at the other side of the shared boundary
26160  if (nh_first_node_pt == h_first_node_pt &&
26161  nh_last_node_pt == h_last_node_pt)
26162  {
26163  // Mark the face elements as done
26164  shared_face_done[nonhalo_face_ele_pt] = true;
26165  shared_face_done[halo_face_ele_pt] = true;
26166 
26167  // Break the loop for (ih < nhalo_face_shared_ele)
26168  break;
26169  } // if (nh_first_node_pt == h_first_node_pt &&
26170  // nh_last_node_pt == h_last_node_pt)
26171  else if (nh_first_node_pt == h_last_node_pt &&
26172  nh_last_node_pt == h_first_node_pt)
26173  {
26174  // Mark the face elements as done
26175  shared_face_done[nonhalo_face_ele_pt] = true;
26176  shared_face_done[halo_face_ele_pt] = true;
26177 
26178  // Break the loop for (ih < nhalo_face_shared_ele)
26179  break;
26180  } // else if (nh_first_node_pt == h_last_node_pt &&
26181  // nh_last_node_pt == h_first_node_pt)
26182 
26183  } // if (face_done[halo_face_ele_pt])
26184 
26185  } // for (ih < nhalo_face_shared_ele)
26186 
26187  } // for (inh < nnonhalo_face_shared_ele)
26188 
26189  // The number of done shared face elements MUST be the same as the
26190  // sum of the nonhalo and halo shared boundary face elements
26191  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
26192  shared_face_done.size())
26193  {
26194  std::ostringstream error_message;
26195  error_message << "The number of DONE shared boundary face elements ("
26196  << shared_face_done.size()
26197  << ") is not the same\n as the sum of"
26198  << "the nonhalo face shared boundary elements ("
26199  << nnonhalo_face_shared_ele
26200  << ")\nand the halo face shared "
26201  << "boundary elements (" << nhalo_face_shared_ele
26202  << ") for the\n/"
26203  << "current boundary (" << shd_bnd_id << ")\n\n";
26204  throw OomphLibError(
26205  error_message.str(),
26206  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26207  OOMPH_EXCEPTION_LOCATION);
26208  }
26209 #endif // #ifdef PARANOID
26210 
26211  // -------------------------------------------------------------
26212  // Now sort the face elements
26213  // -------------------------------------------------------------
26214 
26215  // We already have the shared face elements that make the shared
26216  // boundary now sort them to create a contiguous boundary
26217 
26218  // Clear the already done face elements
26219  shared_face_done.clear();
26220 
26221  unsigned nsorted_face_ele = 0;
26222 
26223  // Storing for the sorting nodes extracted from the face elements
26224  std::list<Node*> sorted_nodes;
26225 
26226  // Get the root face element
26227  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
26228  nsorted_face_ele++;
26229 
26230  // Mark face as done
26231  shared_face_done[root_face_ele_pt] = true;
26232 
26233  // The initial and final node on the list
26234  const unsigned nnodes_root = root_face_ele_pt->nnode();
26235  Node* first_node_pt = root_face_ele_pt->node_pt(0);
26236  Node* last_node_pt = root_face_ele_pt->node_pt(nnodes_root - 1);
26237 
26238  // Push back on the list the new nodes
26239  sorted_nodes.push_back(first_node_pt);
26240  sorted_nodes.push_back(last_node_pt);
26241 
26242  // Sort the face elements
26243  while (nsorted_face_ele < nnonhalo_face_shared_ele)
26244  {
26245  // Flag to indicate when a node was added
26246  bool node_added = false;
26247 
26248  // Start from the next edge since we have already added the
26249  // previous one as the initial face element
26250  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
26251  {
26252  FiniteElement* tmp_shared_face_ele_pt =
26253  nonhalo_shared_face_ele_pt[iface];
26254 
26255  // If face has not been sorted
26256  if (!shared_face_done[tmp_shared_face_ele_pt])
26257  {
26258  // Get the number of nodes for the current face element
26259  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
26260 
26261  // Get each individual node
26262  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26263  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes - 1);
26264 
26265  if (left_node_pt == first_node_pt)
26266  {
26267  // Push front the new node
26268  sorted_nodes.push_front(right_node_pt);
26269  first_node_pt = right_node_pt;
26270  node_added = true;
26271  }
26272  else if (left_node_pt == last_node_pt)
26273  {
26274  // Push back the new node
26275  sorted_nodes.push_back(right_node_pt);
26276  last_node_pt = right_node_pt;
26277  node_added = true;
26278  }
26279  else if (right_node_pt == first_node_pt)
26280  {
26281  // Push front the new node
26282  sorted_nodes.push_front(left_node_pt);
26283  first_node_pt = left_node_pt;
26284  node_added = true;
26285  }
26286  else if (right_node_pt == last_node_pt)
26287  {
26288  // Push back the new node
26289  sorted_nodes.push_back(left_node_pt);
26290  last_node_pt = left_node_pt;
26291  node_added = true;
26292  }
26293 
26294  if (node_added)
26295  {
26296  // Mark as done only if one of its nodes has been added to
26297  // the list
26298  shared_face_done[tmp_shared_face_ele_pt] = true;
26299  nsorted_face_ele++;
26300 
26301  // Break the for
26302  break;
26303  }
26304 
26305  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26306 
26307  } // for (iface < nnonhalo_face_shared_ele)
26308 
26309  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26310 
26311  // Here we can safely delete the face elements, they are no longer
26312  // required
26313 
26314  // First the nonhalo face elements
26315  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26316  {
26317  delete nonhalo_shared_face_ele_pt[inh];
26318  nonhalo_shared_face_ele_pt[inh] = 0;
26319  } // for (inh < nnonhalo_face_shared_ele)
26320 
26321 #ifdef PARANOID
26322  // ... then the halo face elements
26323  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26324  {
26325  delete halo_shared_face_ele_pt[ih];
26326  halo_shared_face_ele_pt[ih] = 0;
26327  } // for (inh < nhalo_face_shared_ele)
26328 #endif
26329 
26330  // ------------------------------------------------
26331  // Now copy the nodes to the output container
26332  // ------------------------------------------------
26333  // Get the number of nodes in the container
26334  const unsigned n_nodes = sorted_nodes.size();
26335 
26336  // First resize the container
26337  tmp_segment_nodes.resize(1);
26338  tmp_segment_nodes[0].resize(n_nodes);
26339 
26340  // Counter
26341  unsigned counter = 0;
26342 
26343  // Loop over the list of nodes and copy them in the output container
26344  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26345  it != sorted_nodes.end();
26346  it++)
26347  {
26348  tmp_segment_nodes[0][counter] = (*it);
26349  counter++;
26350  } // Loop over sorted nodes
26351  }
26352 
26353  //=====start of get_required_elemental_information_load_balance_helper====
26354  /// \short Helper function to get the required elemental information from
26355  /// the element that will be sent to iproc processor.
26356  /// This info. involves the association of the element to a boundary or
26357  /// region.
26358  //========================================================================
26359  template<class ELEMENT>
26362  unsigned& iproc,
26363  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
26364  FiniteElement* ele_pt)
26365  {
26366  // Check if the element is associated with the original boundaries
26367  const unsigned nbound = this->initial_shared_boundary_id();
26368 
26369  // Get the number of processors
26370  const unsigned nproc = this->communicator_pt()->nproc();
26371 
26372  // ------------------------------------------------------------------
26373  // Stores the information regarding the boundaries associated to the
26374  // element (it that is the case)
26375  Vector<unsigned> associated_boundaries;
26376  Vector<unsigned> face_index_on_boundary;
26377 
26378  unsigned counter_face_indexes = 0;
26379 
26380  for (unsigned b = 0; b < nbound; b++)
26381  {
26382  // Get the number of elements associated to boundary i
26383  const unsigned nboundary_ele = nboundary_element(b);
26384  for (unsigned e = 0; e < nboundary_ele; e++)
26385  {
26386  if (ele_pt == this->boundary_element_pt(b, e))
26387  {
26388  // Keep track of the boundaries associated to the element
26389  associated_boundaries.push_back(b);
26390  // Get the face index
26391  face_index_on_boundary.push_back(face_index_at_boundary(b, e));
26392  counter_face_indexes++;
26393 #ifdef PARANOID
26394  if (counter_face_indexes > 2)
26395  {
26396  std::stringstream error_message;
26397  error_message
26398  << "A triangular element can not have more than two of its faces "
26399  << "on a boundary!!!\n\n";
26400  throw OomphLibError(error_message.str(),
26401  "RefineableTriangleMesh::get_required_"
26402  "elemental_information_helper()",
26403  OOMPH_EXCEPTION_LOCATION);
26404  }
26405 #else
26406  // Already found 2 face indexes on the same boundary?
26407  if (counter_face_indexes == 2)
26408  {
26409  break;
26410  }
26411 #endif // #ifdef PARANOID
26412 
26413  } // if (ele_pt == this->boundary_element_pt(b,e))
26414 
26415  } // (e < nboundary_ele)
26416 
26417  } // (b < nbound)
26418 
26419  // If the element is associated to any boundary then package all the
26420  // relevant info
26421  const unsigned nassociated_boundaries = associated_boundaries.size();
26422  if (nassociated_boundaries > 0)
26423  {
26424  Flat_packed_unsigneds.push_back(1);
26425 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26426  Flat_packed_unsigneds_string.push_back(
26427  "The element is a boundary element");
26428 #endif
26429  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26430 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26431  std::stringstream junk;
26432  junk << "The elements is associated to " << nassociated_boundaries
26433  << " boundaries";
26434  Flat_packed_unsigneds_string.push_back(junk.str());
26435 #endif
26436 
26437  // Package the ids of the associated boundaries and the
26438  // corresponding face index for each boundary (if the element is a
26439  // corner element, it will have two faces associated to the
26440  // boundary)
26441  for (unsigned i = 0; i < nassociated_boundaries; i++)
26442  {
26443  unsigned b = associated_boundaries[i];
26444  Flat_packed_unsigneds.push_back(b);
26445 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26446  std::stringstream junk;
26447  junk << "Element associated to boundary " << b << " of "
26448  << nassociated_boundaries << " total associated boundaries";
26449  Flat_packed_unsigneds_string.push_back(junk.str());
26450 #endif
26451  unsigned f = face_index_on_boundary[i];
26452  Flat_packed_unsigneds.push_back(f);
26453 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26454  std::stringstream junk2;
26455  junk2 << "Face index " << f << " for associated boundary " << b;
26456  Flat_packed_unsigneds_string.push_back(junk2.str());
26457 #endif
26458  }
26459 
26460  // If the element is associated to any boundary then we should
26461  // check if the mesh has regions, if that is the case then we need
26462  // to check to which region the boundary element does belong
26463 
26464  // If the mesh has regions we should look for the element
26465  // associated to a boundary and a specified region
26466  Vector<Vector<unsigned>> associated_boundaries_and_regions;
26467  Vector<unsigned> face_index_on_boundary_and_region;
26468 
26469  // Now check for the case when we have regions in the mesh
26470  const unsigned n_regions = this->nregion();
26471  if (n_regions > 1)
26472  {
26473  // Used to count the number of faces associated with
26474  // boundary-regions
26475  unsigned counter_face_indexes_in_regions = 0;
26476  // Loop over the boundaries
26477  for (unsigned b = 0; b < nbound; b++)
26478  {
26479  // Go through each region by getting the region id
26480  for (unsigned i_reg = 0; i_reg < n_regions; i_reg++)
26481  {
26482  // Get thre region id associated with the (i_reg)-th region
26483  const unsigned region_id =
26484  static_cast<unsigned>(this->Region_attribute[i_reg]);
26485 
26486  // Loop over all elements associated with the current boundary
26487  // and the i_reg-th region and check if the element is part of
26488  // any region
26489  const unsigned nele_in_region =
26490  this->nboundary_element_in_region(b, region_id);
26491  for (unsigned ee = 0; ee < nele_in_region; ee++)
26492  {
26493  // Check if the boundary-region element is the same as the
26494  // element
26495  if (ele_pt ==
26496  this->boundary_element_in_region_pt(b, region_id, ee))
26497  {
26498  // Storage for the boundary and region associated to the
26499  // element
26500  Vector<unsigned> bound_and_region(2);
26501 
26502  // Keep track of the boundaries associated to the element
26503  bound_and_region[0] = b;
26504  // Keep track of the regions associated to the element
26505  bound_and_region[1] = region_id;
26506  // Add the boundaries and regions in the storage to be
26507  // sent to other processors
26508  associated_boundaries_and_regions.push_back(bound_and_region);
26509  // Get the face index and keep track of it
26510  face_index_on_boundary_and_region.push_back(
26511  this->face_index_at_boundary_in_region(b, region_id, ee));
26512 
26513  // Increase the number of faces of the element associated
26514  // to boundary-regions
26515  counter_face_indexes_in_regions++;
26516 
26517 #ifdef PARANOID
26518  if (counter_face_indexes_in_regions > 2)
26519  {
26520  std::stringstream error_message;
26521  error_message << "A triangular element can not have more "
26522  "than two of its\n"
26523  << "faces on a boundary!!!\n\n";
26524  throw OomphLibError(error_message.str(),
26525  "RefineableTriangleMesh::get_required_"
26526  "elemental_information_helper()",
26527  OOMPH_EXCEPTION_LOCATION);
26528  } // if (counter_face_indexes_in_regions > 2)
26529 #endif
26530 
26531  } // The element is a boundary-region element
26532 
26533  } // for (ee < nele_in_region)
26534 
26535  } // for (i_reg < n_regions)
26536 
26537  } // for (b < nbound)
26538 
26539  } // if (n_regions > 1)
26540 
26541  // Now package the info. to be sent to other processors
26542  const unsigned nassociated_boundaries_and_regions =
26543  associated_boundaries_and_regions.size();
26544  if (nassociated_boundaries_and_regions > 0)
26545  {
26546  Flat_packed_unsigneds.push_back(1);
26547 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26548  Flat_packed_unsigneds_string.push_back(
26549  "The element is associated to boundaries and regions");
26550 #endif
26551 
26552  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26553 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26554  std::stringstream junk;
26555  junk << "The element is associated to "
26556  << nassociated_boundaries_and_regions << " boundaries-regions";
26557  Flat_packed_unsigneds_string.push_back(junk.str());
26558 #endif
26559 
26560  // Package the ids of the associated boundaries, regions and the
26561  // corresponding face index for each boundary-region (if the
26562  // element is a corner element, it will have two faces
26563  // associated to the boundary-region)
26564  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26565  {
26566  const unsigned b = associated_boundaries_and_regions[i][0];
26567  Flat_packed_unsigneds.push_back(b);
26568 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26569  std::stringstream junk;
26570  junk << "Element associated to boundary " << b << " of "
26571  << nassociated_boundaries_and_regions
26572  << " total associated boundaries-regions";
26573  Flat_packed_unsigneds_string.push_back(junk.str());
26574 #endif
26575 
26576  const unsigned r = associated_boundaries_and_regions[i][1];
26577  Flat_packed_unsigneds.push_back(r);
26578 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26579  std::stringstream junk2;
26580  junk2 << "Element associated to region " << r << " of "
26581  << nassociated_boundaries_and_regions
26582  << " total associated boundaries-regions";
26583  Flat_packed_unsigneds_string.push_back(junk2.str());
26584 #endif
26585 
26586  const unsigned f = face_index_on_boundary_and_region[i];
26587  Flat_packed_unsigneds.push_back(f);
26588 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26589  std::stringstream junk3;
26590  junk3 << "Face index " << f << " for associated boundary-region ("
26591  << b << "-" << r << ")";
26592  Flat_packed_unsigneds_string.push_back(junk3.str());
26593 #endif
26594  } // for (i < nassociated_boundaries_and_regions)
26595  } // if (nassociated_boundaries_and_regions > 0)
26596  else
26597  {
26598  Flat_packed_unsigneds.push_back(0);
26599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26600  Flat_packed_unsigneds_string.push_back(
26601  "The element is NOT associated to boundaries and regions");
26602 #endif
26603  } // else if (nassociated_boundaries_and_regions > 0)
26604  }
26605  else
26606  {
26607  Flat_packed_unsigneds.push_back(0);
26608 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26609  Flat_packed_unsigneds_string.push_back(
26610  "The element is not associated to any original boundary");
26611 #endif
26612  }
26613 
26614  // ------------------------------------------------------------
26615  // Now review if the element is associated to a shared boundary
26616 
26617  // Store the shared boundaries, and therefore the face indexes
26618  // associated to the element
26619  Vector<unsigned> associated_shared_boundaries;
26620  Vector<unsigned> face_index_on_shared_boundary;
26621 
26622  // Get the shared boundaries in this processor
26623  Vector<unsigned> my_rank_shared_boundaries_ids;
26624  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26625 
26626  // Get the number of shared boundaries
26627  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26628  // Loop over the shared boundaries
26629  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26630  {
26631  // Get the boundary id
26632  const unsigned sb = my_rank_shared_boundaries_ids[i];
26633 
26634  // Get the number of elements associated to shared boundary sb
26635  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26636  for (unsigned e = 0; e < nboundary_ele; e++)
26637  {
26638  if (ele_pt == this->shared_boundary_element_pt(sb, e))
26639  {
26640  // Keep track of the boundaries associated to the element
26641  associated_shared_boundaries.push_back(sb);
26642  // Get the face index
26643  face_index_on_shared_boundary.push_back(
26644  this->face_index_at_shared_boundary(sb, e));
26645  }
26646  } // (e < nboundary_ele)
26647  } // (i < nmy_rank_shd_bnd)
26648 
26649  // If the element is associated to a shared boundary then package
26650  // all the relevant info
26651  const unsigned nassociated_shared_boundaries =
26652  associated_shared_boundaries.size();
26653  if (nassociated_shared_boundaries > 0)
26654  {
26655  Flat_packed_unsigneds.push_back(3);
26656 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26657  Flat_packed_unsigneds_string.push_back(
26658  "The element is a shared boundary element");
26659 #endif
26660  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26661 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26662  std::stringstream junk;
26663  junk << "The elements is associated to " << nassociated_shared_boundaries
26664  << "shared boundaries";
26665  Flat_packed_unsigneds_string.push_back(junk.str());
26666 #endif
26667 
26668  // Package the ids of the associated boundaries
26669  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26670  {
26671  const unsigned b = associated_shared_boundaries[i];
26672  Flat_packed_unsigneds.push_back(b);
26673 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26674  std::stringstream junk;
26675  junk << "Element associated to shared boundary " << b << " of "
26676  << nassociated_shared_boundaries << " total associated boundaries";
26677  Flat_packed_unsigneds_string.push_back(junk.str());
26678 #endif
26679 
26680  const unsigned f = face_index_on_shared_boundary[i];
26681  Flat_packed_unsigneds.push_back(f);
26682 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26683  std::stringstream junk2;
26684  junk2 << "Face index " << f << " for associated shared boundary " << b;
26685  Flat_packed_unsigneds_string.push_back(junk2.str());
26686 #endif
26687  }
26688  }
26689  else
26690  {
26691  Flat_packed_unsigneds.push_back(0);
26692 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26693  Flat_packed_unsigneds_string.push_back(
26694  "The element is not associated to any shared boundary");
26695 #endif
26696  }
26697 
26698  // Now check if the element is haloed with any processor
26699 
26700  // Store the index of the haloed element with the jproc
26701  Vector<Vector<unsigned>> index_haloed(nproc);
26702 
26703  // Loop over the processors
26704  for (unsigned jproc = 0; jproc < nproc; jproc++)
26705  {
26706  // Get the number of haloed elements with jproc
26707  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26708  // Loop over the haloed elements with jproc
26709  for (unsigned ihd = 0; ihd < n_haloed_jproc; ihd++)
26710  {
26711  // Is a haloed element?
26712  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26713  {
26714  // Store the haloed index with the jproc processor
26715  index_haloed[jproc].push_back(ihd);
26716  // Break the searching with the jproc processor
26717  break;
26718  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26719 
26720  } // for (ihd < n_haloed_jproc)
26721 
26722  } // for (jproc < nproc)
26723 
26724  // Send the haloed info.
26725  // Loop over the processors
26726  for (unsigned jproc = 0; jproc < nproc; jproc++)
26727  {
26728  // Is the element haloed with the jproc processor
26729  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26730  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26731 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26732  Flat_packed_unsigneds_string.push_back(
26733  "The number of haloed indexes the element is with processor jproc");
26734 #endif
26735  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26736  {
26737  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26738 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26739  Flat_packed_unsigneds_string.push_back(
26740  "The haloed index of the element with jproc");
26741 #endif
26742  } // for (ihd < n_index_haloed_jproc)
26743 
26744  } // for (jproc < nproc)
26745  }
26746 
26747  //======================================================================
26748  /// \short Helper function to add nodes on a new domain as a result of
26749  /// load balance
26750  //======================================================================
26751  template<class ELEMENT>
26753  unsigned& iproc,
26754  Vector<Vector<FiniteElement*>>& f_halo_ele_pt,
26755  Vector<Node*>& new_nodes_on_domain,
26756  Node* nod_pt)
26757  {
26758  // Attempt to add this node to the new domain
26759  const unsigned nnew_nodes_on_domain = new_nodes_on_domain.size();
26760  const unsigned new_added_node_index =
26761  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26762 
26763  // If it was added then the new index should match the size of the storage
26764  if (new_added_node_index == nnew_nodes_on_domain)
26765  {
26766  Flat_packed_unsigneds.push_back(1);
26767 
26768 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26769  std::stringstream junk;
26770  junk << "Node needs to be constructed [size="
26771  << Flat_packed_unsigneds.size() << "]; last entry: "
26772  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
26773  Flat_packed_unsigneds_string.push_back(junk.str());
26774 #endif
26775 
26776  // This helper function gets all the required information for the
26777  // specified node and stores it into MPI-sendable information
26778  // so that a new copy can be made on the receiving process
26779  get_required_nodal_information_load_balance_helper(
26780  f_halo_ele_pt, iproc, nod_pt);
26781  }
26782  else // It was already added
26783  {
26784  Flat_packed_unsigneds.push_back(0);
26785 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26786  std::stringstream junk;
26787  junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
26788  << "]; last entry: "
26789  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
26790 
26791  Flat_packed_unsigneds_string.push_back(junk.str());
26792 #endif
26793 
26794  // This node has been already added, so tell the other process
26795  // its index in the equivalent storage
26796  Flat_packed_unsigneds.push_back(new_added_node_index);
26797 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26798  Flat_packed_unsigneds_string.push_back("new added node index");
26799 #endif
26800  }
26801  }
26802 
26803  //======start of get_required_nodal_information_load_balance_helper=======
26804  /// Helper function to get the required nodal information from an
26805  /// haloed node so that a fully-functional halo node (and therefore element)
26806  /// can be created on the receiving process
26807  //========================================================================
26808  template<class ELEMENT>
26811  Vector<Vector<FiniteElement*>>& f_halo_ele_pt,
26812  unsigned& iproc,
26813  Node* nod_pt)
26814  {
26815  unsigned my_rank = this->communicator_pt()->my_rank();
26816  const unsigned nproc = this->communicator_pt()->nproc();
26817 
26818  // Tell the halo copy of this node how many values there are
26819  // [NB this may be different for nodes within the same element, e.g.
26820  // when using Lagrange multipliers]
26821  unsigned n_val = nod_pt->nvalue();
26822  Flat_packed_unsigneds.push_back(n_val);
26823 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26824  Flat_packed_unsigneds_string.push_back("Number of values");
26825 #endif
26826 
26827  unsigned n_dim = nod_pt->ndim();
26828 
26829  // Default number of previous values to 1
26830  unsigned n_prev = 1;
26831  if (this->Time_stepper_pt != 0)
26832  {
26833  // Add number of history values to n_prev
26834  n_prev = this->Time_stepper_pt->ntstorage();
26835  }
26836 
26837  // -----------------------------------------------------
26838  // Is the node on an original boundary?
26839  // Store the original boundaries where the node may be
26840  Vector<unsigned> original_boundaries;
26841  // Loop over the original boundaries of the mesh and check if live
26842  // on one of them
26843  const unsigned n_bnd = this->initial_shared_boundary_id();
26844  for (unsigned bb = 0; bb < n_bnd; bb++)
26845  {
26846  // Which boundaries (could be more than one) is it on?
26847  if (nod_pt->is_on_boundary(bb))
26848  {
26849  original_boundaries.push_back(bb);
26850  }
26851  }
26852 
26853  const unsigned n_original_boundaries = original_boundaries.size();
26854  // Is the node on any original boundary?
26855  if (n_original_boundaries > 0)
26856  {
26857  // Indicate that the node is on an original boundary
26858  Flat_packed_unsigneds.push_back(2);
26859 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26860  Flat_packed_unsigneds_string.push_back(
26861  "Node is on the original boundaries");
26862 #endif
26863 
26864  Flat_packed_unsigneds.push_back(n_original_boundaries);
26865 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26866  std::stringstream junk;
26867  junk << "Node is on " << n_original_boundaries << " original boundaries";
26868  Flat_packed_unsigneds_string.push_back(junk.str());
26869 #endif
26870 
26871  // Loop over the original boundaries the node is on
26872  for (unsigned i = 0; i < n_original_boundaries; i++)
26873  {
26874  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26875 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26876  std::stringstream junk;
26877  junk << "Node is on boundary " << original_boundaries[i] << " of "
26878  << nb;
26879  Flat_packed_unsigneds_string.push_back(junk.str());
26880 #endif
26881  // Get the boundary coordinate of the node
26882  Vector<double> zeta(1);
26883  nod_pt->get_coordinates_on_boundary(original_boundaries[i], zeta);
26884  Flat_packed_doubles.push_back(zeta[0]);
26885  }
26886  }
26887  else
26888  {
26889  // Indicate that the node is NOT on an original boundary
26890  Flat_packed_unsigneds.push_back(0);
26891 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26892  Flat_packed_unsigneds_string.push_back(
26893  "Node is on any original boundary");
26894 #endif
26895  }
26896 
26897  // -------------------------------------------------------
26898  // Is the node on shared boundaries?
26899  bool node_on_shared_boundary = false;
26900  // Loop over the shared boundaries with the iproc processors and
26901  // check if live on one of them
26902  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26903  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26904  {
26905  // Get the boundary id
26906  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26907  // Which boundaries (could be more than one) is it on?
26908  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26909  {
26910  node_on_shared_boundary = true;
26911  break;
26912  }
26913  }
26914 
26915  // If the node live on any of the shared boundaries with the iproc
26916  // processor then just get the node number according to the
26917  // sorted_shared_boundary_node_pt() scheme and send it accross
26918  if (node_on_shared_boundary)
26919  {
26920  Flat_packed_unsigneds.push_back(1);
26921 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26922  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26923 #endif
26924 
26925  // Store the shared boundaries where the node is on
26926  Vector<unsigned> shd_boundaries;
26927  // Loop over the shared boundaries with the iproc processor
26928  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26929  {
26930  // Get the boundary id
26931  const unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26932  // Which boundaries (could be more than one) is it on?
26933  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26934  {
26935  shd_boundaries.push_back(i_bnd);
26936  }
26937  }
26938 
26939  // Get the number of shared boundaries the node is on
26940  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26941  // Send the number of shared boundaries the node is on
26942  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26943 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26944  std::stringstream junk;
26945  junk << "Node is on " << n_shd_bnd_is_on << " shared boundaries";
26946  Flat_packed_unsigneds_string.push_back(junk.str());
26947 #endif
26948 
26949  // Loop over the shared boundaries to send their ids
26950  for (unsigned i = 0; i < n_shd_bnd_is_on; i++)
26951  {
26952  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26953 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26954  std::stringstream junk;
26955  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26956  Flat_packed_unsigneds_string.push_back(junk.str());
26957 #endif
26958  }
26959 
26960  // Given that the node is on at least one boundary get the index
26961  // of the node in one of the boundaries and send this index
26962  unsigned shared_boundary_id = shd_boundaries[0];
26963  // Get the number of nodes on the given shared boundary
26964  const unsigned n_nodes_on_shared_boundary =
26965  nsorted_shared_boundary_node(shared_boundary_id);
26966  // Store the index of the node on the shared boundary
26967  unsigned index_node_on_shared_boundary;
26968 #ifdef PARANOID
26969  // Flag to know if the node has been found
26970  bool found_index_node_on_shared_boundary = false;
26971 #endif
26972  // Loop over the nodes on the shared boundary to find the node
26973  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26974  {
26975  // Get the i-th node on the shared boundary
26976  Node* shared_node_pt =
26977  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26978  // Is the node we are looking for
26979  if (shared_node_pt == nod_pt)
26980  {
26981  // Store the index
26982  index_node_on_shared_boundary = i;
26983 #ifdef PARANOID
26984  // Mark as found
26985  found_index_node_on_shared_boundary = true;
26986 #endif
26987  break; // break
26988  }
26989 
26990  } // for (i < nnodes_on_shared_boundary)
26991 
26992 #ifdef PARANOID
26993  if (!found_index_node_on_shared_boundary)
26994  {
26995  std::ostringstream error_message;
26996  error_message << "The index of the node on boundary ("
26997  << shared_boundary_id << ") was not found.\n"
26998  << "The node coordinates are (" << nod_pt->x(0) << ","
26999  << nod_pt->x(1) << ").\n";
27000  throw OomphLibError(
27001  error_message.str(),
27002  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27003  OOMPH_EXCEPTION_LOCATION);
27004  }
27005 #endif
27006  // Send the index of the node on the shared boundary
27007  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
27008 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27009  std::stringstream junk2;
27010  junk2 << "Node index on boundary " << boundaries[0] << " is "
27011  << index_node_on_shared_boundary;
27012  Flat_packed_unsigneds_string.push_back(junk2.str());
27013 #endif
27014 
27015  } // if (node_on_shared_boundary)
27016  else
27017  {
27018  // The node is not on a shared boundary
27019  Flat_packed_unsigneds.push_back(0);
27020 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27021  Flat_packed_unsigneds_string.push_back(
27022  "Node is not on a shared boundary");
27023 #endif
27024  }
27025 
27026  // ----------------------------------------------------------------
27027  // Is the node on any shared boundary where the receiver processor
27028  // is not involved?
27029 
27030  // Now check if the node is on a shared boundary created by the
27031  // current processor (my_rank) and other processor different that
27032  // the iproc processor. This info. will help to complete the sending
27033  // of halo(ed) information between processors
27034 
27035  // Flag to know if the node is on a shared boundary with other
27036  // processor
27037  bool node_on_shared_boundary_with_other_processors = false;
27038  // Count the number of other shared boundaries it could be on
27039  unsigned nshared_boundaries_with_other_processors_have_node = 0;
27040 
27041  // Loop over the shared boundaries of the sent processor (my_rank)
27042  // and other processors (jproc)
27043  for (unsigned jproc = 0; jproc < nproc; jproc++)
27044  {
27045  // Do not search with the iproc processor, that was done before
27046  // above
27047  if (jproc != iproc)
27048  {
27049  // Get the number of shared boundaries with the jproc processor
27050  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
27051  // Loop over the shared boundaries
27052  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
27053  {
27054  // Get the boundary id
27055  const unsigned j_shd_bnd =
27056  this->shared_boundaries_ids(my_rank, jproc, bb);
27057  // Is the node part of this boundary?
27058  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
27059  {
27060  // DEBP("Sending to");
27061  // DEBP(iproc);
27062  // DEBP("Pair of procs where other shared");
27063  // DEBP(my_rank);
27064  // DEBP(jproc);
27065  // DEBP(i_bnd);
27066  node_on_shared_boundary_with_other_processors = true;
27067  // Increase the counter for the number of shared boundaries
27068  // with other processors the node is on
27069  nshared_boundaries_with_other_processors_have_node++;
27070  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
27071 
27072  } // for (bb<n_jshd_bnd)
27073 
27074  } // if (jproc != iproc)
27075 
27076  } // for (jproc < nproc)
27077 
27078  // If the node is on a shared boundary with another processor
27079  // (my_rank, jproc), then send the flag and look for the info.
27080  if (node_on_shared_boundary_with_other_processors)
27081  {
27082  Flat_packed_unsigneds.push_back(4);
27083 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27084  Flat_packed_unsigneds_string.push_back(
27085  "Node is on shared boundary no related with the received processor: 4");
27086 #endif
27087 
27088  // The number of packages of information that will be sent to the
27089  // "iproc" processor. This helps to know how many packages of data
27090  // read from the received processor
27091  Flat_packed_unsigneds.push_back(
27092  nshared_boundaries_with_other_processors_have_node);
27093 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27094  std::stringstream junk;
27095  junk << "Number of other shared boundaries that the node is on: "
27096  << nshared_boundaries_with_other_processors_have_node;
27097  Flat_packed_unsigneds_string.push_back(junk.str());
27098 #endif
27099 
27100  // Counter to ensure that the correct number of data has been sent
27101  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
27102  // Loop over the shared boundaries with other processors and get:
27103  // 1) The processors defining the shared boundary
27104  // 2) The shared boundary id
27105  // 3) The index of the node on the shared boundary
27106  Vector<unsigned> other_processor_1;
27107  Vector<unsigned> other_processor_2;
27108  Vector<unsigned> shd_bnd_ids;
27109  Vector<unsigned> indexes;
27110  // Loop over the processors again
27111  for (unsigned jproc = 0; jproc < nproc; jproc++)
27112  {
27113  // Do not search with the iproc processor, that was done before
27114  // above
27115  if (jproc != iproc)
27116  {
27117  // Get the number of shared boundaries with the jproc
27118  // processor
27119  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
27120  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
27121  {
27122  // Get the boundary id
27123  const unsigned j_shd_bnd =
27124  this->shared_boundaries_ids(my_rank, jproc, bb);
27125  // Is the node part of this boundary?
27126  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
27127  {
27128  // Include the first processor
27129  other_processor_1.push_back(my_rank);
27130  // Include the second processor
27131  other_processor_2.push_back(jproc);
27132  // Include the shared boundary id
27133  shd_bnd_ids.push_back(j_shd_bnd);
27134  // Increase the counter for found shared boundaries with
27135  // other processors
27136  counter_shd_bnd_with_other_procs_have_node++;
27137  }
27138 
27139  } // for (bb < nshared_bnd)
27140 
27141  } // if (jproc != iproc)
27142 
27143  } // for (jproc < nproc)
27144 
27145  // Get the indexes of the node on all the shared boundaries where
27146  // it was found
27147  const unsigned n_other_processors = other_processor_1.size();
27148  // Loop over the processors where the node was found
27149  for (unsigned i = 0; i < n_other_processors; i++)
27150  {
27151  // Get the shared boundary id
27152  unsigned shd_bnd_id = shd_bnd_ids[i];
27153  // Get the number of nodes on that shared boundary
27154  const unsigned n_nodes_on_shd_bnd =
27155  nsorted_shared_boundary_node(shd_bnd_id);
27156 
27157 #ifdef PARANOID
27158  bool found_index_node_on_shared_boundary = false;
27159 #endif
27160  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
27161  {
27162  // Get the i-th shared boundary node
27163  Node* shared_node_pt = sorted_shared_boundary_node_pt(shd_bnd_id, i);
27164  // Is the same node?
27165  if (shared_node_pt == nod_pt)
27166  {
27167  // DEBP(i_node);
27168  // DEBP(nod_pt->x(0));
27169  // DEBP(nod_pt->x(1));
27170  // Include the index of the node
27171  indexes.push_back(i);
27172 #ifdef PARANOID
27173  // Mark as found the node
27174  found_index_node_on_shared_boundary = true;
27175 #endif
27176  break;
27177  } // if (shared_node_pt == nod_pt)
27178 
27179  } // for (i < n_nodes_on_shd_bnd)
27180 
27181 #ifdef PARANOID
27182  if (!found_index_node_on_shared_boundary)
27183  {
27184  std::ostringstream error_message;
27185  error_message << "The index of the node on boundary (" << shd_bnd_id
27186  << "), shared by other processors\nwas not found.\n"
27187  << "The node coordinates are (" << nod_pt->x(0) << ","
27188  << nod_pt->x(1) << ").\n";
27189  throw OomphLibError(
27190  error_message.str(),
27191  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27192  OOMPH_EXCEPTION_LOCATION);
27193  }
27194 #endif
27195  } // for (i < n_other_processors)
27196 
27197  // Now send the info. but first check that the number of found
27198  // nodes be the same that the previously found shared boundaries
27199  // with the node
27200 #ifdef PARANOID
27201  if (counter_shd_bnd_with_other_procs_have_node !=
27202  nshared_boundaries_with_other_processors_have_node)
27203  {
27204  std::ostringstream error_message;
27205  error_message << "The number of shared boundaries where the node is on "
27206  << "is different:\n"
27207  << "nshared_boundaries_with_other_processors_have_node: ("
27208  << nshared_boundaries_with_other_processors_have_node
27209  << ")\n"
27210  << "counter_shd_bnd_with_other_procs_have_node: ("
27211  << counter_shd_bnd_with_other_procs_have_node << ")\n";
27212  throw OomphLibError(
27213  error_message.str(),
27214  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27215  OOMPH_EXCEPTION_LOCATION);
27216  } // if (counter_shd_bnd_with_other_procs_have_node !=
27217  // nshared_boundaries_with_other_processors_have_node)
27218 #endif
27219 
27220  // Loop over the info. to send it
27221  for (unsigned i = 0; i < n_other_processors; i++)
27222  {
27223  Flat_packed_unsigneds.push_back(other_processor_1[i]);
27224 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27225  std::stringstream junk1;
27226  junk1 << "Processor where the other shared boundary "
27227  << "has the node: " << other_processor_1[i];
27228  Flat_packed_unsigneds_string.push_back(junk1.str());
27229 #endif
27230 
27231  Flat_packed_unsigneds.push_back(other_processor_2[i]);
27232 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27233  std::stringstream junk2;
27234  junk2 << "Processor where the other shared boundary "
27235  << "has the node: " << other_processor_2[i];
27236  Flat_packed_unsigneds_string.push_back(junk2.str());
27237 #endif
27238 
27239  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
27240 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27241  std::stringstream junk3;
27242  junk3 << "Other shared boundary id where the node is on"
27243  << boundaries[i];
27244  Flat_packed_unsigneds_string.push_back(junk3.str());
27245 #endif
27246 
27247  Flat_packed_unsigneds.push_back(indexes[i]);
27248 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27249  std::stringstream junk4;
27250  junk4 << "Node index on other shared boundary " << boundaries[i]
27251  << " is " << indexes[i];
27252  Flat_packed_unsigneds_string.push_back(junk4.str());
27253 #endif
27254 
27255  } // for (i < n_other_processors)
27256 
27257  } // if (node_on_shared_boundary_with_other_processors)
27258  else
27259  {
27260  Flat_packed_unsigneds.push_back(0);
27261 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27262  Flat_packed_unsigneds_string.push_back(
27263  "Node is on any shared boundary with other processors");
27264 #endif
27265  } // else if (node_on_shared_boundary_with_other_processors)
27266 
27267  // It may still be possible that the node be shared with the
27268  // processor that receives the info. but it is neither on shared
27269  // boundary with the receiver processor nor on a shared boundary
27270  // with others processors. Think in the next case:
27271 
27272  // |-----|-----| - The elements in processor 3 need to be sent to
27273  // | 4 | 3 | processor 1, and that is all
27274  // |-----*-----| - When processor 1 receives the data from node (*)
27275  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
27276  // |-----|-----| that the node is also on the shared boundary that
27277  // processor 1 and 2 or processor 1 and 4 share.
27278 
27279  // This problem become even worse if there would be more processors
27280  // between processor 3 and 2, or/and processor 3 and 4. Think in
27281  // triangles sharing the node (*)
27282 
27283  // To solve this check if the node that we are trying to send is
27284  // part of the halo elements of the curreent processor (my_rank)
27285  // with any other processor (we need to check with all the
27286  // processors and not just with the processors to which we will send
27287  // to cover more cases)
27288 
27289  // Store the halo element number with jproc where the node was found
27290  Vector<Vector<unsigned>> halo_element_number(nproc);
27291  // Store the node number on the halo element where the node was found
27292  Vector<Vector<unsigned>> halo_node_number_in_halo_element(nproc);
27293 
27294  // Loop over the processor
27295  for (unsigned jproc = 0; jproc < nproc; jproc++)
27296  {
27297  // Get the number of halo elements with the jproc processor
27298  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27299  // Loop over the halo elements
27300  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27301  {
27302  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27303  // Get the number of nodes of the halo element
27304  const unsigned n_node = halo_ele_pt->nnode();
27305  // Loop over the nodes
27306  for (unsigned n = 0; n < n_node; n++)
27307  {
27308  // Is the node part of the ih-th halo element with jproc
27309  if (nod_pt == halo_ele_pt->node_pt(n))
27310  {
27311  halo_element_number[jproc].push_back(jh);
27312  halo_node_number_in_halo_element[jproc].push_back(n);
27313  // break with the nodes, no need to look for more nodes in
27314  // the element
27315  break;
27316  } // if (nod_pt == halo_ele_pt->node_pt(n))
27317 
27318  } // for (n < n_node)
27319 
27320  } // for (jh < n_halo_jproc)
27321 
27322  } // for (jproc < nproc)
27323 
27324  // Send the info. related with if the node is on halo elements with
27325  // any processor
27326 
27327  // Loop over the processors
27328  for (unsigned jproc = 0; jproc < nproc; jproc++)
27329  {
27330  // Get the number of halo elements with jproc processor where the
27331  // node is
27332  const unsigned n_jproc_halo_ele_node_is_on =
27333  halo_element_number[jproc].size();
27334  // Send the number of halo elements with jproc where the node is
27335  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27336 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27337  std::stringstream junk5;
27338  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27339  << "elements with " << jproc << "-th processor";
27340  Flat_packed_unsigneds_string.push_back(junk5.str());
27341 #endif
27342  // Send the halo elements indexes (which will be haloed elements
27343  // indexes in the receiver processor), and the indexes of the
27344  // nodes in each halo element
27345  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27346  {
27347  // The halo element index
27348  const unsigned halo_element_index = halo_element_number[jproc][i];
27349  Flat_packed_unsigneds.push_back(halo_element_index);
27350 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27351  std::stringstream junk6;
27352  junk6 << "Halo element index is (" << halo_element_index
27353  << ") with processor (" << jproc << ")";
27354  Flat_packed_unsigneds_string.push_back(junk6.str());
27355 #endif
27356  // The node index on the halo element
27357  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27358  Flat_packed_unsigneds.push_back(node_index);
27359 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27360  std::stringstream junk7;
27361  junk7 << "The node index on the halo element index is (" << node_index;
27362  Flat_packed_unsigneds_string.push_back(junk7.str());
27363 #endif
27364 
27365  } // for (i < n_jproc_halo_ele_node_is_on)
27366 
27367  } // for (jproc < nproc)
27368 
27369  // Now check if it is required to send the info. of the node. If the
27370  // node is not on a shared boundary with the iproc processor then we
27371  // need to send the info.
27372 
27373  // Flag to indicate if it is on a halo element with the iproc
27374  // processor. If this flag is true then there is no need to send the
27375  // info. to create the node, in the receiver processor the info is
27376  // copied from the indicated haloed element-node
27377  bool on_halo_element_with_iproc_processor = false;
27378  if (halo_element_number[iproc].size() > 0)
27379  {
27380  on_halo_element_with_iproc_processor = true;
27381  } // if (halo_element_number[iproc].size() > 0)
27382 
27383  // if (!node_on_shared_boundary)
27384  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27385  {
27386  // Send all the info. to create it
27387 
27388  // Is the Node algebraic? If so, send its ref values and
27389  // an indication of its geometric objects if they are stored
27390  // in the algebraic mesh
27391  AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
27392  if (alg_nod_pt != 0)
27393  {
27394  // The external mesh should be algebraic
27395  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
27396 
27397  // Get default node update function ID
27398  unsigned update_id = alg_nod_pt->node_update_fct_id();
27399  Flat_packed_unsigneds.push_back(update_id);
27400 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27401  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27402 #endif
27403 
27404  // Get reference values at default...
27405  unsigned n_ref_val = alg_nod_pt->nref_value();
27406  Flat_packed_unsigneds.push_back(n_ref_val);
27407 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27408  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27409 #endif
27410  for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
27411  {
27412  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27413  }
27414 
27415  // Access geometric objects at default...
27416  unsigned n_geom_obj = alg_nod_pt->ngeom_object();
27417  Flat_packed_unsigneds.push_back(n_geom_obj);
27418 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27419  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27420 #endif
27421  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
27422  {
27423  GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
27424 
27425  // Check this against the stored geometric objects in mesh
27426  unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
27427 
27428  // Default found index to zero
27429  unsigned found_geom_object = 0;
27430  for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
27431  {
27432  if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
27433  {
27434  found_geom_object = i_list;
27435  }
27436  }
27437  Flat_packed_unsigneds.push_back(found_geom_object);
27438 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27439  Flat_packed_unsigneds_string.push_back("Found geom object");
27440 #endif
27441  }
27442  } // (if alg_nod_pt!=0)
27443 
27444  // Is it a SolidNode?
27445  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
27446  if (solid_nod_pt != 0)
27447  {
27448  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
27449  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
27450  {
27451  for (unsigned t = 0; t < n_prev; t++)
27452  {
27453  Flat_packed_doubles.push_back(
27454  solid_nod_pt->variable_position_pt()->value(t, i_val));
27455  }
27456  }
27457 
27458  Vector<double> values_solid_node;
27459  solid_nod_pt->add_values_to_vector(values_solid_node);
27460  const unsigned nvalues_solid_node = values_solid_node.size();
27461  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27462 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27463  std::stringstream junk;
27464  junk << "Number of values solid node: " << nvalues_solid_node;
27465  Flat_packed_unsigneds_string.push_back(junk.str());
27466 #endif
27467  for (unsigned i = 0; i < nvalues_solid_node; i++)
27468  {
27469  Flat_packed_doubles.push_back(values_solid_node[i]);
27470  }
27471  }
27472 
27473  // Finally copy info required for all node types
27474  for (unsigned i_val = 0; i_val < n_val; i_val++)
27475  {
27476  for (unsigned t = 0; t < n_prev; t++)
27477  {
27478  Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
27479  }
27480  }
27481 
27482  // Now do positions
27483  for (unsigned idim = 0; idim < n_dim; idim++)
27484  {
27485  for (unsigned t = 0; t < n_prev; t++)
27486  {
27487  Flat_packed_doubles.push_back(nod_pt->x(t, idim));
27488  // DEBP(nod_pt->x(t,idim));
27489  }
27490  }
27491 
27492  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27493  }
27494 
27495  //======================================================================
27496  /// \short Helper function to create elements on the loop
27497  /// process based on the info received in
27498  /// send_and_received_elements_nodes_info
27499  //======================================================================
27500  template<class ELEMENT>
27502  unsigned& iproc,
27503  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27504  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27505  received_old_haloed_element_pt,
27506  Vector<FiniteElement*>& new_elements_on_domain,
27507  Vector<Node*>& new_nodes_on_domain,
27508  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27509  other_proc_shd_bnd_node_pt,
27510  Vector<Vector<Vector<unsigned>>>& global_node_names,
27511  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27512  Vector<Node*>& global_shared_node_pt)
27513  {
27514 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27515  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27516  << " Bool: New element needs to be constructed "
27517  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27518  << std::endl;
27519 #endif
27520 
27521  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27522  {
27523  // Create a new element from the communicated values
27524  // and coords from the process that located zeta
27525  GeneralisedElement* new_el_pt = new ELEMENT;
27526 
27527  // Add the new element to the mesh - Do not add the element yet
27528  // since no retained elements still need to be deleted
27529  // this->add_element_pt(new_el_pt);
27530 
27531  // Cast to the FE pointer
27532  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(new_el_pt);
27533 
27534  // Add the element to the new elements in the domain container
27535  new_elements_on_domain.push_back(f_el_pt);
27536 
27537  // Set any additional information for the element
27538  this->add_element_load_balance_helper(
27539  iproc, received_old_haloed_element_pt, f_el_pt);
27540 
27541  // Add nodes to the new element
27542  unsigned n_node = f_el_pt->nnode();
27543  for (unsigned j = 0; j < n_node; j++)
27544  {
27545  Node* new_nod_pt = 0;
27546 
27547  // Call the add halo node helper function
27548  add_received_node_load_balance_helper(new_nod_pt,
27549  f_haloed_ele_pt,
27550  received_old_haloed_element_pt,
27551  new_nodes_on_domain,
27552  other_proc_shd_bnd_node_pt,
27553  iproc,
27554  j,
27555  f_el_pt,
27556  global_node_names,
27557  node_name_to_global_index,
27558  global_shared_node_pt);
27559  }
27560  }
27561  else // the element already exists
27562  {
27563 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27564  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27565  << " Index of existing element "
27566  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27567  << std::endl;
27568 #endif
27569 
27570  // Incrase the index, we do anything else with the element
27571  Counter_for_flat_packed_unsigneds++;
27572 
27573  } // else the element already exists
27574  }
27575 
27576  //========start of add_element_load_balance_helper=====================
27577  /// \short Helper function to create elements on the loop
27578  /// process based on the info received in
27579  /// send_and_received_elements_nodes_info
27580  /// This function is in charge of verify if the element is associated
27581  /// to a boundary and associate to it if that is the case
27582  //======================================================================
27583  template<class ELEMENT>
27585  const unsigned& iproc,
27586  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27587  received_old_haloed_element_pt,
27588  FiniteElement* ele_pt)
27589  {
27590  // Get the number of processors
27591  const unsigned nproc = this->communicator_pt()->nproc();
27592 
27593 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27594  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27595  << " Bool: Element is associated to a boundary "
27596  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27597  << std::endl;
27598 #endif
27599 
27600  // Is on an original boundary?
27601  const unsigned is_on_original_boundary =
27602  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27603  if (is_on_original_boundary == 1)
27604  {
27605 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27606  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27607  << " How many boundaries are associated with the element "
27608  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27609  << std::endl;
27610 #endif
27611  // Number of boundaries the element is associated with
27612  const unsigned nassociated_boundaries =
27613  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27614 
27615  // Loop over the associated boundaries
27616  for (unsigned b = 0; b < nassociated_boundaries; b++)
27617  {
27618 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27619  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27620  << " Boundary associated to the element "
27621  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27622  << std::endl;
27623 #endif
27624 
27625  // The boundary id
27626  const unsigned bnd =
27627  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27628 
27629 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27630  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27631  << " Face index of the element "
27632  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27633  << std::endl;
27634 #endif
27635 
27636  // The face index
27637  const unsigned face_index =
27638  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27639 
27640  // Associate the element with the boundary and establish as many
27641  // face indexes it has
27642  this->Boundary_element_pt[bnd].push_back(ele_pt);
27643  this->Face_index_at_boundary[bnd].push_back(face_index);
27644 
27645  } // (b < nassociated_boundaries)
27646 
27647  // Here read the info. regarding the boundary-region of the element
27648 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27649  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27650  << " Bool: Element is associated to a boundary-region "
27651  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27652  << std::endl;
27653 #endif
27654 
27655  // Is the element associated to a boundary-region?
27656  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27657  {
27658 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27659  oomph_info
27660  << "Rec:" << Counter_for_flat_packed_unsigneds
27661  << " How many boundaries-regions are associated with the element "
27662  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27663  << std::endl;
27664 #endif
27665  // Number of boundary-regions the element is associated
27666  const unsigned nassociated_boundaries_and_regions =
27667  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27668 
27669  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27670  {
27671 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27672  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27673  << " Boundary associated to the element "
27674  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27675  << std::endl;
27676 #endif
27677  // The boundary id
27678  const unsigned bnd =
27679  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27680 
27681 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27682  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27683  << " Region associated to the element "
27684  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27685  << std::endl;
27686 #endif
27687  // The region id
27688  const unsigned region =
27689  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27690 
27691 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27692  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27693  << " Face index of the element in boundary-region "
27694  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27695  << std::endl;
27696 #endif
27697  const unsigned face_index =
27698  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27699 
27700  // Associate the element with the boundary-regions and establish
27701  // as many face indexes it has
27702  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27703  this->Face_index_region_at_boundary[bnd][region].push_back(
27704  face_index);
27705 
27706  } // for (br < nassociated_boundaries_and_regions)
27707 
27708  } // Is the element associated with a boundary-region?
27709 
27710  } // The element is associated with an original boundary
27711 #ifdef PARANOID
27712  else
27713  {
27714  if (is_on_original_boundary != 0)
27715  {
27716  std::ostringstream error_message;
27717  error_message
27718  << "The current element is not on an original boundary, this should\n"
27719  << "be indicated by a zero flag. However, the read value for\n"
27720  << "that flag is (" << is_on_original_boundary << ").\n\n";
27721  throw OomphLibError(
27722  error_message.str(),
27723  "RefineableTriangleMesh::add_element_load_balance_helper()",
27724  OOMPH_EXCEPTION_LOCATION);
27725  } // if (is_on_shared_boundary != 0)
27726  }
27727 #endif
27728 
27729 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27730  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27731  << " Bool: Element is associated to a shared boundary "
27732  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27733  << std::endl;
27734 #endif
27735 
27736  // Is the element a shared boundary element?
27737  const unsigned is_on_shared_boundary =
27738  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27739  if (is_on_shared_boundary == 3)
27740  {
27741 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27742  oomph_info
27743  << "Rec:" << Counter_for_flat_packed_unsigneds
27744  << " How many shared boundaries are associated with the element "
27745  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27746  << std::endl;
27747 #endif
27748 
27749  // The number of shared boundaries the element is associated
27750  const unsigned nassociated_shared_boundaries =
27751  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27752 
27753  // Loop over the associated shared boundaries
27754  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27755  {
27756 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27757  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27758  << " Shared boundary associated to the element "
27759  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27760  << std::endl;
27761 #endif
27762  const unsigned bnd =
27763  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27764 
27765 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27766  oomph_info
27767  << "Rec:" << Counter_for_flat_packed_unsigneds
27768  << " Face index of the element associated to the shared boundary "
27769  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27770  << std::endl;
27771 #endif
27772 
27773  const unsigned face_index =
27774  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27775 
27776  this->add_shared_boundary_element(bnd, ele_pt);
27777  this->add_face_index_at_shared_boundary(bnd, face_index);
27778 
27779  } // (b < nassociated_shared_boundaries)
27780 
27781  } // The element is associted with a shared boundary
27782 #ifdef PARANOID
27783  else
27784  {
27785  if (is_on_shared_boundary != 0)
27786  {
27787  std::ostringstream error_message;
27788  error_message
27789  << "The current element is not on a shared boundary, this should\n"
27790  << "be indicated by a zero flag. However, the read value for\n"
27791  << "that flag is (" << is_on_shared_boundary << ").\n\n";
27792  throw OomphLibError(
27793  error_message.str(),
27794  "RefineableTriangleMesh::add_element_load_balance_helper()",
27795  OOMPH_EXCEPTION_LOCATION);
27796  } // if (is_on_shared_boundary != 0)
27797  }
27798 #endif
27799 
27800  // Now check if the element is a haloed element in the sender
27801  // processor with any other processor
27802 
27803  // Loop over the processors
27804  for (unsigned jproc = 0; jproc < nproc; jproc++)
27805  {
27806 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27807  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27808  << " Bool: Number of haloed indexes of the element with the "
27809  << jproc << " processor: "
27810  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27811  << std::endl;
27812 #endif
27813  // Is the element haloed with the jproc processor
27814  const unsigned n_index_haloed_jproc =
27815  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27816  // Loop over the number of haloed indexes
27817  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27818  {
27819 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27820  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27821  << " Bool: The haloed element index with the " << jproc
27822  << " processor: "
27823  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27824  << std::endl;
27825 #endif
27826  const unsigned haloed_index =
27827  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27828 
27829  // Set the halod element in the proper storage
27830  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27831 
27832  } // for (ihd < n_index_haloed_jproc)
27833 
27834  } // for (jproc < nproc)
27835  }
27836 
27837  //======================================================================
27838  /// \short Helper function to add a new node from load balance
27839  //======================================================================
27840  template<class ELEMENT>
27842  Node*& new_nod_pt,
27843  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27844  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27845  received_old_haloed_element_pt,
27846  Vector<Node*>& new_nodes_on_domain,
27847  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27848  other_proc_shd_bnd_node_pt,
27849  unsigned& iproc,
27850  unsigned& node_index,
27851  FiniteElement* const& new_el_pt,
27852  Vector<Vector<Vector<unsigned>>>& global_node_names,
27853  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27854  Vector<Node*>& global_shared_node_pt)
27855  {
27856  // Given the node, received information about it from processor
27857  // iproc, construct it on the current process
27858 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27859  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27860  << " Bool: New node needs to be constructed "
27861  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27862  << std::endl;
27863 #endif
27864  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27865  {
27866  // Construct a new node based upon sent information, or copy a node
27867  // from one of the shared boundaries
27868  construct_new_node_load_balance_helper(new_nod_pt,
27869  f_haloed_ele_pt,
27870  received_old_haloed_element_pt,
27871  new_nodes_on_domain,
27872  other_proc_shd_bnd_node_pt,
27873  iproc,
27874  node_index,
27875  new_el_pt,
27876  global_node_names,
27877  node_name_to_global_index,
27878  global_shared_node_pt);
27879  }
27880  else
27881  {
27882 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27883  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27884  << " Index of existing halo node "
27885  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27886  << std::endl;
27887 #endif
27888  // The node already exist, copy it from the indicated position
27889 
27890  // Get the node's index, and copy it
27891  new_nod_pt = new_nodes_on_domain
27892  [Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
27893 
27894  // Set the node in the current element
27895  new_el_pt->node_pt(node_index) = new_nod_pt;
27896  }
27897  }
27898 
27899  //============start_of_construct_new_node_load_balance_helper()=========
27900  /// \short Helper function which constructs a new node (on an
27901  /// element) with the information sent from the load balance
27902  /// process
27903  //======================================================================
27904  template<class ELEMENT>
27906  Node*& new_nod_pt,
27907  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27908  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27909  received_old_haloed_element_pt,
27910  Vector<Node*>& new_nodes_on_domain,
27911  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27912  other_proc_shd_bnd_node_pt,
27913  unsigned& iproc,
27914  unsigned& node_index,
27915  FiniteElement* const& new_el_pt,
27916  Vector<Vector<Vector<unsigned>>>& global_node_names,
27917  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27918  Vector<Node*>& global_shared_node_pt)
27919  {
27920  // Get the number of processors
27921  const unsigned nproc = this->communicator_pt()->nproc();
27922  // Get the rank of the current processor
27923  const unsigned my_rank = this->communicator_pt()->my_rank();
27924 
27925  // The first entry indicates the number of values at this new Node
27926  //(which may be different across the same element e.g. Lagrange multipliers)
27927 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27928  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27929  << " Number of values of external halo node "
27930  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27931  << std::endl;
27932 #endif
27933  unsigned n_val = Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27934 
27935  // Null TimeStepper for now
27936  TimeStepper* time_stepper_pt = this->Time_stepper_pt;
27937  // Default number of previous values to 1
27938  unsigned n_prev = time_stepper_pt->ntstorage();
27939 
27940  // ------------------------------------------------------
27941  // Check if the node is on an original boundary
27942 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27943  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27944  << " Is the node on an original boundary "
27945  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27946  << std::endl;
27947 #endif
27948 
27949  // Flag to indicate if the node is on original boundaries
27950  const unsigned node_on_original_boundaries =
27951  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27952 
27953  // Store the original boundaries where the node is on
27954  Vector<unsigned> original_boundaries_node_is_on;
27955  // Store the zeta coordinates of the node on the original boundaries
27956  Vector<double> zeta_coordinates;
27957  // Store the number of original boundaries the node is on
27958  unsigned n_original_boundaries_node_is_on = 0;
27959 
27960  if (node_on_original_boundaries == 2)
27961  {
27962  // How many original boundaries does the node live on?
27963 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27964  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27965  << " Number of boundaries the node is on: "
27966  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27967  << std::endl;
27968 #endif
27969  n_original_boundaries_node_is_on =
27970  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27971 
27972  // Resize the containers
27973  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27974  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27975 
27976  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
27977  {
27978  // Boundary number
27979 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27980  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27981  << " Node is on boundary "
27982  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27983  << std::endl;
27984 #endif
27985  original_boundaries_node_is_on[i] =
27986  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27987  zeta_coordinates[i] =
27988  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
27989  }
27990 
27991  } // if (node_on_original_boundaries==2)
27992 #ifdef PARANOID
27993  else
27994  {
27995  if (node_on_original_boundaries != 0)
27996  {
27997  std::ostringstream error_message;
27998  error_message
27999  << "The current node is not on an original boundary, this should\n"
28000  << "be indicated by a zero flag. However, the read value for\n"
28001  << "that flag is (" << node_on_original_boundaries << ").\n\n";
28002  throw OomphLibError(
28003  error_message.str(),
28004  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28005  OOMPH_EXCEPTION_LOCATION);
28006  } // if (node_on_original_boundaries != 0)
28007  }
28008 #endif
28009 
28010  // --------------------------------------------------------------
28011  // Check if the node was on a shared boundary with the iproc
28012  // processor
28013 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28014  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28015  << " Is node on shared boundary? "
28016  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28017  << std::endl;
28018 #endif
28019  const unsigned is_node_on_shared_boundary =
28020  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28021  if (is_node_on_shared_boundary == 1)
28022  {
28023  // How many shared boundaries does the node live on?
28024 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28025  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28026  << " Number of boundaries the node is on: "
28027  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28028  << std::endl;
28029 #endif
28030  const unsigned n_shd_bnd_node_is_on =
28031  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28032  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
28033  for (unsigned i = 0; i < n_shd_bnd_node_is_on; i++)
28034  {
28035  // Shared boundary number
28036 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28037  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28038  << " Node is on boundary "
28039  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28040  << std::endl;
28041 #endif
28042  shd_bnds_node_is_on[i] =
28043  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28044  }
28045 
28046  // Get the index of the node on the shared boundary
28047 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28048  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28049  << " Index of node on boundary "
28050  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28051  << std::endl;
28052 #endif
28053  // Get the node index of the node on the shared boundary
28054  unsigned node_index_on_shared_boundary =
28055  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28056 
28057  // Get the pointer to the node with the received info.
28058  new_nod_pt = this->sorted_shared_boundary_node_pt(
28059  shd_bnds_node_is_on[0], node_index_on_shared_boundary);
28060 
28061  } // if (is_node_on_shared_boundary == 1)
28062 #ifdef PARANOID
28063  else
28064  {
28065  if (is_node_on_shared_boundary != 0)
28066  {
28067  std::ostringstream error_message;
28068  error_message
28069  << "The current node is not on a shared boundary, this should\n"
28070  << "be indicated by a zero flag. However, the read value for\n"
28071  << "that flag is (" << is_node_on_shared_boundary << ").\n\n";
28072  throw OomphLibError(
28073  error_message.str(),
28074  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28075  OOMPH_EXCEPTION_LOCATION);
28076  } // if (node_on_shared_boundary != 0)
28077  }
28078 #endif
28079 
28080  // ------------------------------------------------------------
28081  // Is the node on a shared boundary with other processor?
28082 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28083  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28084  << " Is the node on shared boundaries with other processors "
28085  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28086  << std::endl;
28087 #endif
28088 
28089  // Is the node in shared boundaries no associated with the
28090  // receiver processor
28091  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
28092  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28093 
28094  // The containers where to store the info.
28095  Vector<unsigned> other_processor_1;
28096  Vector<unsigned> other_processor_2;
28097  Vector<unsigned> other_shared_boundaries;
28098  Vector<unsigned> other_indexes;
28099 
28100  // How many shared bounaries with other processors the node lives on
28101  unsigned n_shd_bnd_with_other_procs_have_node = 0;
28102 
28103  // Is the node on shared boundaries with other processors
28104  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28105  {
28106 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28107  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28108  << " In how many shared boundaries with other "
28109  << "processors is the node "
28110  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28111  << std::endl;
28112 #endif
28113 
28114  // How many nodes on other shared boundaries were found
28115  n_shd_bnd_with_other_procs_have_node =
28116  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28117 
28118  // Resize the containers
28119  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
28120  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
28121  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
28122  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
28123 
28124  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28125  {
28126 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28127  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28128  << " Processor where the other shared boundary"
28129  << "has the node"
28130  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28131  << std::endl;
28132 #endif
28133  // Read the other processor 1
28134  other_processor_1[i] =
28135  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28136 
28137 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28138  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28139  << " Processor where the other shared boundary"
28140  << "has the node"
28141  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28142  << std::endl;
28143 #endif
28144  // Read the other processor 2
28145  other_processor_2[i] =
28146  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28147 
28148 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28149  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28150  << " Other shared boundary id where the node is on: "
28151  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28152  << std::endl;
28153 #endif
28154 
28155  // Read the other shared boundary id
28156  other_shared_boundaries[i] =
28157  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28158 
28159 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28160  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28161  << " Node index on the other shared boundary "
28162  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28163  << std::endl;
28164 #endif
28165 
28166  // Read the node index on the other shared boundary
28167  other_indexes[i] =
28168  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28169 
28170  } // for (i < n_shd_bnd_with_other_procs_have_node)
28171 
28172  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28173 #ifdef PARANOID
28174  else
28175  {
28176  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
28177  {
28178  std::ostringstream error_message;
28179  error_message
28180  << "The current node is not on a shared boundary with\n"
28181  << "other processors, this should be indicated by a zero flag.\n"
28182  << "However, the read value for that flag is ("
28183  << is_the_node_in_shared_boundaries_with_other_processors << ").\n\n";
28184  throw OomphLibError(
28185  error_message.str(),
28186  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28187  OOMPH_EXCEPTION_LOCATION);
28188  }
28189  }
28190 #endif
28191 
28192  // ------------------------------------------------------------
28193  // Receive the info. to check if the node is on a haloed element
28194  // with any processor
28195 
28196  // Store the halo element number with jproc where the node was found
28197  Vector<Vector<unsigned>> halo_element_number(nproc);
28198  // Store the node number on the halo element where the node was found
28199  Vector<Vector<unsigned>> halo_node_number_in_halo_element(nproc);
28200 
28201  // Loop over the processors
28202  for (unsigned jproc = 0; jproc < nproc; jproc++)
28203  {
28204 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28205  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28206  << " The node is on "
28207  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28208  << " halo elements with " << jproc << " processor"
28209  << std::endl;
28210 #endif
28211  // Get the number of halo elements with jproc processor where the
28212  // node was found
28213  const unsigned n_jproc_halo_ele_node_is_on =
28214  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28215 
28216  // Resize the containers
28217  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
28218  halo_node_number_in_halo_element[jproc].resize(
28219  n_jproc_halo_ele_node_is_on);
28220 
28221  // Read halo elements indexes (which are indexes of the halo
28222  // elements of the sender processor (iproc) with other processors
28223  // (included my_rank)
28224  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
28225  {
28226  // Get the halo element index in the jproc processor
28227 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28228  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28229  << " The halo element index where the node is on "
28230  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28231  << std::endl;
28232 #endif
28233  // Get the node index on the halo element
28234  const unsigned halo_ele_index =
28235  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28236 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28237  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28238  << " The node index on the halo element where the node "
28239  << "is on "
28240  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28241  << std::endl;
28242 #endif
28243  const unsigned node_index_on_halo_ele =
28244  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28245 
28246  // Store the halo element number
28247  halo_element_number[jproc][i] = halo_ele_index;
28248  // Store the index of on the haloed element
28249  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
28250 
28251  } // for (i < n_jproc_halo_ele_node_is_on)
28252 
28253  } // for (jproc < nproc)
28254 
28255  // Store the node pointers obtained from the indicated halo elements
28256  // (use a set to check for the case when the node pointer is
28257  // different)
28258  std::set<Node*> set_haloed_node_pt;
28259 
28260  // Store the node pointer obtained from the haloed elements
28261  Node* haloed_node_pt = 0;
28262 
28263  // Flag to indicate if it is on a haloed element of the current
28264  // processor with the iproc processor. If this flag is true then
28265  // there is no need to read the info. to create the node, only copy
28266  // the node from the indicated haloed element-node
28267  bool on_haloed_element_with_iproc_processor = false;
28268  if (halo_element_number[my_rank].size() > 0)
28269  {
28270  // The node is part of the haloed element in the current processor
28271  // (my_rank) with the receiver processor
28272  on_haloed_element_with_iproc_processor = true;
28273 
28274  // Get the number of haloed elements in the current processor
28275  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28276  // Loop over the different haloed indexes, and get the nodes
28277  // instances from all the indicated haloed elements (all of them
28278  // should be the same)
28279  for (unsigned i = 0; i < n_haloed_indexes; i++)
28280  {
28281  // Get the haloed element numbers where the node is on
28282  const unsigned haloed_index = halo_element_number[my_rank][i];
28283  // Get the node index on the haloed element
28284  const unsigned haloed_node_index =
28285  halo_node_number_in_halo_element[my_rank][i];
28286 
28287  // Get the haloed element (with iproc)
28288  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28289  // Get the node on the indicated node number
28290  Node* tmp_haloed_node_pt =
28291  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28292 
28293  // Set the pointer for the obtained haloed node
28294  haloed_node_pt = tmp_haloed_node_pt;
28295 
28296  // Add the node to the set of node pointers
28297  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28298 
28299 #ifdef PARANOID
28300  if (set_haloed_node_pt.size() > 1)
28301  {
28302  std::ostringstream error_message;
28303  error_message
28304  << "When adding the " << haloed_node_index << " node of the "
28305  << haloed_index << "-th haloed element\n"
28306  << "in the currrent processor with the " << iproc << " processor"
28307  << "it was found that\nthe node pointer is different from the other"
28308  << "instances of the node.\nIt means we have a repeated node."
28309  << "This are the node coordinates of the previous node instances\n"
28310  << "The last entry is for the just added node with a different "
28311  "node\n"
28312  << "pointer\n";
28313  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28314  it != set_haloed_node_pt.end();
28315  it++)
28316  {
28317  error_message << "Node: (" << (*it)->x(0) << ", " << (*it)->x(1)
28318  << ")\n";
28319  }
28320  error_message << "\n";
28321  throw OomphLibError(
28322  error_message.str(),
28323  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28324  OOMPH_EXCEPTION_LOCATION);
28325  }
28326 #endif
28327 
28328  } // for (i < n_haloed_indexes)
28329 
28330  } // if (halo_element_number[iproc].size() > 0)
28331 
28332  // Flag to indicate if the node has been found on a haloed element
28333  // of other processor with the iproc processor
28334  bool found_on_haloed_element_with_other_processor = false;
28335  // Loop over the processors (only until the iproc since no info. of
28336  // higher processors has been received)
28337  for (unsigned jproc = 0; jproc < iproc; jproc++)
28338  {
28339  // Is the node on a halo element with the jproc processor
28340  if (halo_element_number[jproc].size() > 0)
28341  {
28342  // Get the number of halo elements with the jproc processor
28343  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28344  // Loop over the different halo indexes, and get the nodes
28345  // instances from all the indicated halo elements (all of them
28346  // should be the same)
28347  for (unsigned i = 0; i < n_halo_indexes; i++)
28348  {
28349  // Get the haloed element numbers where the node is on
28350  const unsigned haloed_index = halo_element_number[jproc][i];
28351  // Get the node index on the haloed element
28352  const unsigned haloed_node_index =
28353  halo_node_number_in_halo_element[jproc][i];
28354 
28355  // Have we received the indicated element? (Get the haloed
28356  // element on jproc with the iproc processor)
28357  std::map<unsigned, FiniteElement*>::iterator it_map =
28358  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28359  // Have we received the indicated element?
28360  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28361  {
28362  // Set the flag of found element in other processors haloed
28363  // element, in this case in haloed elements of processor
28364  // jproc wiht iproc processor
28365  found_on_haloed_element_with_other_processor = true;
28366 
28367  // Get the element
28368  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28369  // Get the node on the indicated node number
28370  Node* tmp_haloed_node_pt =
28371  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28372 
28373  // Set the pointer for the obtained haloed node
28374  haloed_node_pt = tmp_haloed_node_pt;
28375 
28376  // Add the node to the set of node pointers
28377  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28378 
28379 #ifdef PARANOID
28380  if (set_haloed_node_pt.size() > 1)
28381  {
28382  std::ostringstream error_message;
28383  error_message
28384  << "When adding the " << haloed_node_index << " node of the "
28385  << haloed_index << "-th haloed element "
28386  << "of the " << jproc << " processor\nwith the " << iproc
28387  << " processor, it was found that\n"
28388  << "the node pointer is different from the other\n"
28389  << "instances of the node.\nThis means we have a repeated "
28390  "node.\n"
28391  << "These are the node coordinates of the previous node "
28392  << "instances\n"
28393  << "The last entry is for the just added node with a "
28394  "different\n"
28395  << "node pointer\n";
28396  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28397  it != set_haloed_node_pt.end();
28398  it++)
28399  {
28400  error_message << "Node: (" << (*it)->x(0) << ", " << (*it)->x(1)
28401  << ")\n";
28402  }
28403  error_message << "\n";
28404  throw OomphLibError(error_message.str(),
28405  "RefineableTriangleMesh::construct_new_node_"
28406  "load_balance_helper()",
28407  OOMPH_EXCEPTION_LOCATION);
28408  }
28409 #endif
28410 
28411  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28412  // Have we received the element?
28413 
28414  } // for (i < n_haloed_indexes)
28415 
28416  } // if (halo_element_number[iproc].size() > 0)
28417 
28418  } // for (jproc < nproc)
28419 
28420  // If the node was found in the haloed elements of the current
28421  // processor with the iproc processor, or in the haloed elements of
28422  // any other processor with the iproc processor then copy the node
28423  // pointer (no problem if we overwrite the node info. it should be
28424  // the same node pointer)
28425  if (on_haloed_element_with_iproc_processor ||
28426  found_on_haloed_element_with_other_processor)
28427  {
28428  // Set the node pointer
28429  new_nod_pt = haloed_node_pt;
28430  }
28431 
28432  // Now we have all the info. to decide if the node should be created
28433  // or not
28434 
28435  // First check if the node is a shared boundary node, or if it has
28436  // been found on haloed elements
28437  if (is_node_on_shared_boundary == 1 ||
28438  (on_haloed_element_with_iproc_processor))
28439  {
28440  // We already have the node, we do not need to create it
28441 
28442  // Only check if we need to add boundary info. to the node
28443  if (node_on_original_boundaries == 2)
28444  {
28445  // The node is a boundary node, add the boundary info. before
28446  // adding it to the domain
28447 
28448  // Associate the node to the given boundaries
28449  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28450  {
28451  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28452  // Establish the boundary coordinates for the node
28453  Vector<double> zeta(1);
28454  zeta[0] = zeta_coordinates[i];
28455  new_nod_pt->set_coordinates_on_boundary(
28456  original_boundaries_node_is_on[i], zeta);
28457  }
28458 
28459  } // if (node_on_original_boundaries==2)
28460 
28461  // Add the node to the domain
28462  new_nodes_on_domain.push_back(new_nod_pt);
28463 
28464  // Add the node to the element
28465  new_el_pt->node_pt(node_index) = new_nod_pt;
28466 
28467  } // if (is_node_on_shared_boundary == 1)
28468 
28469  // Now check if the node is on a shared boundary with another
28470  // processor, if that is the case try to find the node that may have
28471  // been already sent by the other processors
28472 
28473  // This flags indicates if the node was found, and then decide if it
28474  // is required to create the node
28475  bool found_node_in_other_shared_boundaries = false;
28476  // Flag to indicate whether the node should be created as a boundary
28477  // node or not. If the node lies on a shared boundary with other
28478  // processor the we create it as a boundary node. The processor from
28479  // which we are receiving info. (iproc) may not know that the node
28480  // lies on an original boundary. If the node lies on an original
28481  // boundary then its info. will be sent by another processor, then
28482  // we can set its boundary info. since the node was constructed as a
28483  // boundary node
28484  bool build_node_as_boundary_node = false;
28485 
28486  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28487  {
28488  // Build the node as a boundary node
28489  build_node_as_boundary_node = true;
28490 
28491  // Try to get the node pointer in case that the node has been
28492  // already sent by the other processors
28493 
28494  // Get the number of initial shared boundaries to correct the
28495  // index of the shared boundary
28496  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28497 
28498  // Add the found nodes in the container, should be the same but
28499  // better check
28500  Vector<Node*> found_node_pt;
28501 
28502  // Now try to find the node in any of the other shared boundaries
28503  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28504  {
28505  unsigned oproc1 = other_processor_1[i];
28506  unsigned oproc2 = other_processor_2[i];
28507 
28508  // Check that we always check with the lower processors number
28509  // first
28510  if (oproc1 > oproc2)
28511  {
28512  oproc2 = oproc1;
28513  oproc1 = other_processor_2[i];
28514  } // if (oproc1 > oproc2)
28515 
28516  // Re-compute the shared boundary id between the other
28517  // processors
28518  const unsigned shd_bnd_id =
28519  other_shared_boundaries[i] - initial_shd_bnd_id;
28520  // Read the index
28521  const unsigned index = other_indexes[i];
28522 
28523  // Check if there are nodes received from the other processor
28524  // and with the given shared boundary
28525  const unsigned n_nodes_on_other_processor =
28526  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28527 
28528  if (n_nodes_on_other_processor > 0)
28529  {
28530  // Check if we can find the index of the node in that other
28531  // processor and shared boundary id
28532  std::map<unsigned, Node*>::iterator it =
28533  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].find(index);
28534 
28535  // If the index exist then get the node pointer
28536  if (it !=
28537  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28538  {
28539  // Mark the node as found
28540  found_node_in_other_shared_boundaries = true;
28541  // Get the node pointer
28542  Node* tmp_node_pt =
28543  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28544  found_node_pt.push_back(tmp_node_pt);
28545  } // if (it!=
28546  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28547 
28548  } // if (n_nodes_on_other_processor > 0)
28549 
28550  } // for (i < n_shd_bnd_with_other_procs_have_node)
28551 
28552  // If the node was found, then all their instances should be the
28553  // same but better check
28554  if (found_node_in_other_shared_boundaries)
28555  {
28556 #ifdef PARANOID
28557  const unsigned ntimes_node_found = found_node_pt.size();
28558  for (unsigned j = 1; j < ntimes_node_found; j++)
28559  {
28560  if (found_node_pt[j - 1] != found_node_pt[j])
28561  {
28562  std::ostringstream error_message;
28563  error_message
28564  << "The instances of the node that was found to be on a\n"
28565  << "shared boundary with other processors are not the same,\n"
28566  << "the coordinates for the nodes are these:\n"
28567  << "(" << found_node_pt[j - 1]->x(0) << ", "
28568  << found_node_pt[j - 1]->x(1) << ")\n"
28569  << "(" << found_node_pt[j]->x(0) << ", " << found_node_pt[j]->x(1)
28570  << ")\n"
28571  << "Not be surprised if they are the same since the node is\n"
28572  << "repeated!!!\n";
28573  throw OomphLibError(
28574  error_message.str(),
28575  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28576  OOMPH_EXCEPTION_LOCATION);
28577 
28578  } // if (found_node_pt[j-1] != found_node_pt[j])
28579 
28580  } // for (j < ntimes_node_found)
28581 #endif
28582 
28583  // Check if the node is a shared boundary node from the current
28584  // processor and the iproc processor, if that is the case, and
28585  // the node is also on a shared boundary with other processor,
28586  // then the pointer should be the same!!!
28587  if (is_node_on_shared_boundary == 1)
28588  {
28589  // The pointer to the node is already assigned, it was
28590  // assigned when thenode was found to be on a shared boundary
28591  // with the iproc processor
28592  if (found_node_pt[0] != new_nod_pt)
28593  {
28594  std::ostringstream error_message;
28595  error_message
28596  << "The pointer of the node that was found to be on a\n"
28597  << "shared boundary with other processor(s) and the pointer\n"
28598  << "of the node on shared boundary with the receiver\n"
28599  << "processor (iproc) are not the same. This means we have a\n"
28600  << "repeated node)\n"
28601  << "The coordinates for the nodes are:\n"
28602  << "(" << found_node_pt[0]->x(0) << ", " << found_node_pt[0]->x(1)
28603  << ")\n"
28604  << "(" << new_nod_pt->x(0) << ", " << new_nod_pt->x(1) << ")\n"
28605  << "Not to be surprised if they are the same since the node is\n"
28606  << "repeated!!!\n";
28607  throw OomphLibError(
28608  error_message.str(),
28609  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28610  OOMPH_EXCEPTION_LOCATION);
28611  } // if (found_node_pt[0] != new_nod_pt)
28612 
28613  } // if (is_node_on_shared_boundary == 1)
28614  else
28615  {
28616  // Take the first instance of the node in case that it was
28617  // found and is not on a shared boundary with the iproc
28618  // processor
28619  new_nod_pt = found_node_pt[0];
28620  }
28621 
28622  } // if (found_node_in_other_shared_boundaries)
28623 
28624  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28625 
28626  // -----------------------------------------------------------------
28627  // Create the node or read the received info if the node is not on a
28628  // shared boundary with the iproc processor and if the node is not
28629  // part of the haloed elements with the iproc processor in the
28630  // current processors
28631  if (is_node_on_shared_boundary != 1 &&
28632  !on_haloed_element_with_iproc_processor)
28633  {
28634  // If the node is on a shared boundary with other processor we
28635  // need to read all the info. since the processor that sent the
28636  // info. did not know that the node is part of another shared
28637  // boundary
28638 
28639  // If the node is not a shared boundary (with any processor), or
28640  // if this is the first time that the info. of the node is
28641  // received from any of the processors with which is has a shared
28642  // boundary, then we create the node
28643 
28644  // Is the node a boundary node or should it be build as a boundary
28645  // node because it is on a shared boundary with other processors
28646  if (node_on_original_boundaries == 2 || build_node_as_boundary_node)
28647  {
28648  // Check if necessary to create the node, or if it has been
28649  // already found in shared boundaries with other processors or
28650  // in the haloed elements with of other processors with the
28651  // iproc processor
28652  if (!found_node_in_other_shared_boundaries ||
28653  !found_on_haloed_element_with_other_processor)
28654  {
28655  // Construct a boundary node
28656  if (time_stepper_pt != 0)
28657  {
28658  new_nod_pt =
28659  new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
28660  }
28661  else
28662  {
28663  new_nod_pt = new_el_pt->construct_boundary_node(node_index);
28664  }
28665 
28666  } // if (!found_node_in_other_shared_boundaries ||
28667  // !found_on_haloed_element_with_other_processor)
28668  else
28669  {
28670  // If the node was found then assign the node to the element
28671  new_el_pt->node_pt(node_index) = new_nod_pt;
28672  } // else if (!found_node_in_other_shared_boundaries ||
28673  // !found_on_haloed_element_with_other_processor)
28674 
28675  // Associate the node to the given boundaries
28676  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28677  {
28678  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28679  // Establish the boundary coordinates for the node
28680  Vector<double> zeta(1);
28681  zeta[0] = zeta_coordinates[i];
28682  new_nod_pt->set_coordinates_on_boundary(
28683  original_boundaries_node_is_on[i], zeta);
28684  }
28685 
28686  } // if (node is on an original boundary)
28687  else
28688  {
28689  // Check if necessary to create the node, or if it has been
28690  // already found in shared boundaries with other processors or
28691  // in the haloed elements with of other processors with the
28692  // iproc processor
28693  if (!found_node_in_other_shared_boundaries ||
28694  !found_on_haloed_element_with_other_processor)
28695  {
28696  // Construct an ordinary (non-boundary) node
28697  if (time_stepper_pt != 0)
28698  {
28699  new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
28700  }
28701  else
28702  {
28703  new_nod_pt = new_el_pt->construct_node(node_index);
28704  }
28705  } // if (!found_node_in_other_shared_boundaries ||
28706  // !found_on_haloed_element_with_other_processor)
28707  else
28708  {
28709  // If the node was found then assign the node to the element
28710  new_el_pt->node_pt(node_index) = new_nod_pt;
28711  } // else // if (!found_node_in_other_shared_boundaries ||
28712  // !found_on_haloed_element_with_other_processor)
28713 
28714  } // else (the node is not a boundary node)
28715 
28716  // ... and gather all its information
28717 
28718  // If the node was found or not in other shared boundaries, this
28719  // is the first time the node is received from this processor
28720  // (iproc), therefore it is added to the vector of nodes received
28721  // from this processor (iproc)
28722  new_nodes_on_domain.push_back(new_nod_pt);
28723 
28724  // Check if necessary to state all the info. to the node if it has
28725  // been already found in shared boundaries with other processors
28726  // or in the haloed elements with of other processors with the
28727  // iproc processor
28728  if (!found_node_in_other_shared_boundaries ||
28729  !found_on_haloed_element_with_other_processor)
28730  {
28731  // Add the node to the general node storage
28732  this->add_node_pt(new_nod_pt);
28733  } // if (!found_node_in_other_shared_boundaries ||
28734  // !found_on_haloed_element_with_other_processor)
28735 
28736  // Is the new constructed node Algebraic?
28737  AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
28738 
28739  // If it is algebraic, its node update functions will
28740  // not yet have been set up properly
28741  if (new_alg_nod_pt != 0)
28742  {
28743  // The AlgebraicMesh is the external mesh
28744  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
28745 
28746  /// The first entry of All_alg_nodal_info contains
28747  /// the default node update id
28748  /// e.g. for the quarter circle there are
28749  /// "Upper_left_box", "Lower right box" etc...
28750 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28751  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28752  << " Alg node update id "
28753  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28754  << std::endl;
28755 #endif
28756 
28757  unsigned update_id =
28758  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28759 
28760  Vector<double> ref_value;
28761 
28762  // The size of this vector is in the next entry
28763  // of All_alg_nodal_info
28764 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28765  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28766  << " Alg node # of ref values "
28767  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28768  << std::endl;
28769 #endif
28770  unsigned n_ref_val =
28771  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28772 
28773  // The reference values themselves are in
28774  // All_alg_ref_value
28775  ref_value.resize(n_ref_val);
28776  for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
28777  {
28778  ref_value[i_ref] =
28779  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28780  }
28781 
28782  Vector<GeomObject*> geom_object_pt;
28783  /// again we need the size of this vector as it varies
28784  /// between meshes; we also need some indication
28785  /// as to which geometric object should be used...
28786 
28787  // The size of this vector is in the next entry
28788  // of All_alg_nodal_info
28789 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28790  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28791  << " Alg node # of geom objects "
28792  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28793  << std::endl;
28794 #endif
28795  unsigned n_geom_obj =
28796  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28797 
28798  // The remaining indices are in the rest of
28799  // All_alg_nodal_info
28800  geom_object_pt.resize(n_geom_obj);
28801  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
28802  {
28803 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28804  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28805  << " Alg node: geom object index "
28806  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28807  << std::endl;
28808 #endif
28809  unsigned geom_index =
28810  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28811  // This index indicates which of the AlgebraicMesh's
28812  // stored geometric objects should be used
28813  // (0 is a null pointer; everything else should have
28814  // been filled in by the specific Mesh). If it
28815  // hasn't been filled in then the update_node_update
28816  // call should fix it
28817  geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
28818  }
28819 
28820  // Check if necessary to state all the info. to the node if it
28821  // has been already found in shared boundaries with other
28822  // processors or in the haloed elements with of other processors
28823  // with the iproc processor
28824  if (!found_node_in_other_shared_boundaries ||
28825  !found_on_haloed_element_with_other_processor)
28826  {
28827  /// For the received update_id, ref_value, geom_object
28828  /// call add_node_update_info
28829  new_alg_nod_pt->add_node_update_info(
28830  update_id, alg_mesh_pt, geom_object_pt, ref_value);
28831 
28832  /// Now call update_node_update
28833  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28834 
28835  } // if (!found_node_in_other_shared_boundaries ||
28836  // !found_on_haloed_element_with_other_processor)
28837 
28838  } // if (new_alg_nod_pt!=0)
28839 
28840  // Check if necessary to state all the info. to the node if it has
28841  // been already found in shared boundaries with other processors
28842  // or in the haloed elements with of other processors with the
28843  // iproc processor
28844  if (!found_node_in_other_shared_boundaries ||
28845  !found_on_haloed_element_with_other_processor)
28846  {
28847  // Is the node a MacroElementNodeUpdateNode?
28848  MacroElementNodeUpdateNode* macro_nod_pt =
28849  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28850 
28851  if (macro_nod_pt != 0)
28852  {
28853  // Need to call set_node_update_info; this requires
28854  // a Vector<GeomObject*> (taken from the mesh)
28855  Vector<GeomObject*> geom_object_vector_pt;
28856 
28857  // Access the required geom objects from the
28858  // MacroElementNodeUpdateMesh
28859  MacroElementNodeUpdateMesh* macro_mesh_pt =
28860  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28861  geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
28862 
28863  // Get local coordinate of node in new element
28864  Vector<double> s_in_macro_node_update_element;
28865  new_el_pt->local_coordinate_of_node(node_index,
28866  s_in_macro_node_update_element);
28867 
28868  // Set node update info for this node
28869  macro_nod_pt->set_node_update_info(
28870  new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
28871  }
28872 
28873  } // if (!found_node_in_other_shared_boundaries ||
28874  // !found_on_haloed_element_with_other_processor)
28875 
28876  // If there are additional values, resize the node
28877  unsigned n_new_val = new_nod_pt->nvalue();
28878 
28879  // Check if necessary to state all the info. to the node if it has
28880  // been already found in shared boundaries with other processors
28881  // or in the haloed elements with of other processors with the
28882  // iproc processor
28883  if (!found_node_in_other_shared_boundaries ||
28884  !found_on_haloed_element_with_other_processor)
28885  {
28886  if (n_val > n_new_val)
28887  {
28888  // If it has been necessary to resize then it may be becuse
28889  // the node is on a FSI boundary, if that is the case we need
28890  // to set a map for these external values
28891 
28892  // Cast to a boundary node
28893  BoundaryNodeBase* bnod_pt =
28894  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28895 
28896  // Create storage, if it doesn't already exist, for the map
28897  // that will contain the position of the first entry of
28898  // this face element's additional values,
28899  if (bnod_pt->index_of_first_value_assigned_by_face_element_pt() == 0)
28900  {
28901  bnod_pt->index_of_first_value_assigned_by_face_element_pt() =
28902  new std::map<unsigned, unsigned>;
28903  }
28904 
28905  // Get pointer to the map
28906  std::map<unsigned, unsigned>* map_pt =
28907  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
28908 
28909  // The id of the face to which this node belong in the bulk
28910  // element
28911  const unsigned id_face = 0;
28912  // We only resize the node values Vector if we haven't done it yet
28913  std::map<unsigned, unsigned>::const_iterator p =
28914  map_pt->find(id_face);
28915 
28916  // If this node hasn't been resized for current id
28917  if (p == map_pt->end())
28918  {
28919  // assign the face element id and the position of the
28920  // first entry to the boundary node
28921  (*map_pt)[id_face] = n_new_val;
28922 
28923  // resize the node vector of values
28924  new_nod_pt->resize(n_val);
28925  }
28926 
28927  } // if (n_val>n_new_val)
28928 
28929  } // if (!found_node_in_other_shared_boundaries ||
28930  // !found_on_haloed_element_with_other_processor)
28931 
28932  // Is the new node a SolidNode?
28933  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
28934  if (solid_nod_pt != 0)
28935  {
28936  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
28937  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
28938  {
28939  for (unsigned t = 0; t < n_prev; t++)
28940  {
28941  double read_data =
28942  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28943 
28944  // Check if necessary to state all the info. to the node if
28945  // it has been already found in shared boundaries with other
28946  // processors or in the haloed elements with of other
28947  // processors with the iproc processor
28948  if (!found_node_in_other_shared_boundaries ||
28949  !found_on_haloed_element_with_other_processor)
28950  {
28951  solid_nod_pt->variable_position_pt()->set_value(
28952  t, i_val, read_data);
28953  } // if (!found_node_in_other_shared_boundaries ||
28954  // !found_on_haloed_element_with_other_processor)
28955  }
28956  }
28957 
28958 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28959  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28960  << " Number of values solid node: "
28961  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28962  << std::endl;
28963 #endif
28964  const unsigned nvalues_solid_node =
28965  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28966  Vector<double> values_solid_node(nvalues_solid_node);
28967  for (unsigned i = 0; i < nvalues_solid_node; i++)
28968  {
28969  values_solid_node[i] =
28970  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28971  }
28972 
28973  // Check if necessary to state all the info. to the node if it
28974  // has been already found in shared boundaries with other
28975  // processors or in the haloed elements with of other processors
28976  // with the iproc processor
28977  if (!found_node_in_other_shared_boundaries ||
28978  !found_on_haloed_element_with_other_processor)
28979  {
28980  unsigned index = 0;
28981  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28982  } // if (!found_node_in_other_shared_boundaries ||
28983  // !found_on_haloed_element_with_other_processor)
28984  }
28985 
28986  // Get copied history values
28987  // unsigned n_val=new_nod_pt->nvalue();
28988  for (unsigned i_val = 0; i_val < n_val; i_val++)
28989  {
28990  for (unsigned t = 0; t < n_prev; t++)
28991  {
28992  double read_data =
28993  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28994 
28995  // Check if necessary to state all the info. to the node if it
28996  // has been already found in shared boundaries with other
28997  // processors or in the haloed elements with of other
28998  // processors with the iproc processor
28999  if (!found_node_in_other_shared_boundaries ||
29000  !found_on_haloed_element_with_other_processor)
29001  {
29002  new_nod_pt->set_value(t, i_val, read_data);
29003  } // if (!found_node_in_other_shared_boundaries ||
29004  // !found_on_haloed_element_with_other_processor)
29005  }
29006  }
29007 
29008  // Get copied history values for positions
29009  unsigned n_dim = new_nod_pt->ndim();
29010  for (unsigned idim = 0; idim < n_dim; idim++)
29011  {
29012  for (unsigned t = 0; t < n_prev; t++)
29013  {
29014  double read_data =
29015  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
29016 
29017  // Check if necessary to state all the info. to the node if it
29018  // has been already found in shared boundaries with other
29019  // processors or in the haloed elements with of other
29020  // processors with the iproc processor
29021  if (!found_node_in_other_shared_boundaries ||
29022  !found_on_haloed_element_with_other_processor)
29023  {
29024  // Copy to coordinate
29025  new_nod_pt->x(t, idim) = read_data;
29026  // DEBP(new_nod_pt->x(t,idim));
29027  } // if (!found_node_in_other_shared_boundaries ||
29028  // !found_on_haloed_element_with_other_processor)
29029  }
29030  }
29031 
29032  } // if (is_node_on_shared_boundary != 1)
29033 
29034  // If the node was not found in other shared boundaries (possibly
29035  // because it is the first time the node has been sent) then copy
29036  // the node to the shared boundaries where it should be, use the
29037  // special container for this cases
29038  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
29039  // shared
29040  // boundaries with
29041  // other processors
29042  !found_node_in_other_shared_boundaries) // The node has not
29043  // been previously
29044  // set as with
29045  // shared with
29046  // other processors
29047  // (first time)
29048  {
29049  // Update the node pointer in all the references of the node
29050  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
29051  other_proc_shd_bnd_node_pt,
29052  other_processor_1,
29053  other_processor_2,
29054  other_shared_boundaries,
29055  other_indexes,
29056  global_node_names,
29057  node_name_to_global_index,
29058  global_shared_node_pt);
29059 
29060  } // if (!found_node_in_other_shared_boundaries)
29061  }
29062 
29063 #endif // #ifdef OOMPH_HAS_MPI
29064 
29065  //======================================================================
29066  /// \short Get the nodes on the boundary (b), these are stored in the
29067  /// segment they belong (also used by the load balance method to
29068  /// re-set the number of segments per boundary after load balance has
29069  /// taken place)
29070  //======================================================================
29071  template<class ELEMENT>
29073  const unsigned& b, Vector<Vector<Node*>>& tmp_segment_nodes)
29074  {
29075  // Clear the data structure were to return the nodes
29076  tmp_segment_nodes.clear();
29077 
29078  // Temporary storage for face elements
29079  Vector<FiniteElement*> face_el_pt;
29080 
29081  // Temporary storage for number of elements adjacent to the boundary
29082  unsigned nel = 0;
29083 
29084  // Temporary storage for elements adjacent to the boundary that have
29085  // a common edge (related with internal boundaries)
29086  unsigned n_repeated_ele = 0;
29087 
29088  // Get the number of regions
29089  const unsigned n_regions = this->nregion();
29090 
29091  // Temporary storage for already visited pair of nodes (edges)
29092  Vector<std::pair<Node*, Node*>> done_nodes_pt;
29093 
29094  // Are there more than one region?
29095  if (n_regions > 1)
29096  {
29097  for (unsigned rr = 0; rr < n_regions; rr++)
29098  {
29099  const unsigned region_id =
29100  static_cast<unsigned>(this->Region_attribute[rr]);
29101 
29102  // Loop over all elements on boundaries in region rr
29103  const unsigned nel_in_region =
29104  this->nboundary_element_in_region(b, region_id);
29105 
29106  // Number of repeated element in region
29107  unsigned nel_repeated_in_region = 0;
29108 
29109  // Only bother to do anything else, if there are elements
29110  // associated with the boundary and the current region
29111  if (nel_in_region > 0)
29112  {
29113  // Flag that activates when a repeated face element is found,
29114  // possibly because we are dealing with an internal boundary
29115  bool repeated = false;
29116 
29117  // Loop over the bulk elements adjacent to boundary b
29118  for (unsigned e = 0; e < nel_in_region; e++)
29119  {
29120  // Get pointer to the bulk element that is adjacent to boundary b
29121  FiniteElement* bulk_elem_pt =
29122  this->boundary_element_in_region_pt(b, region_id, e);
29123 
29124 #ifdef OOMPH_HAS_MPI
29125  // In a distributed mesh only work with nonhalo elements
29126  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
29127  {
29128  // Increase the number of repeated elements
29129  n_repeated_ele++;
29130  // Go for the next element
29131  continue;
29132  }
29133 #endif
29134 
29135  // Find the index of the face of element e along boundary b
29136  int face_index =
29137  this->face_index_at_boundary_in_region(b, region_id, e);
29138 
29139  // Before adding the new element we need to be sure that the
29140  // edge that this element represents has not been already
29141  // added
29142  FiniteElement* tmp_ele_pt =
29143  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
29144 
29145  // Number of nodes in the face element
29146  const unsigned n_nodes = tmp_ele_pt->nnode();
29147 
29148  std::pair<Node*, Node*> tmp_pair = std::make_pair(
29149  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
29150 
29151  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
29152  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
29153 
29154  // Search for repeated nodes
29155  unsigned n_done_nodes = done_nodes_pt.size();
29156  for (unsigned l = 0; l < n_done_nodes; l++)
29157  {
29158  if (tmp_pair == done_nodes_pt[l] ||
29159  tmp_pair_inverse == done_nodes_pt[l])
29160  {
29161  nel_repeated_in_region++;
29162  repeated = true;
29163  break;
29164  }
29165 
29166  } // for (l < n_done_nodes)
29167 
29168  // Create new face element?
29169  if (!repeated)
29170  {
29171  // Add the pair of nodes (edge) to the node dones
29172  done_nodes_pt.push_back(tmp_pair);
29173  // Add the face element to the storage
29174  face_el_pt.push_back(tmp_ele_pt);
29175  }
29176  else
29177  {
29178  // Clean up
29179  delete tmp_ele_pt;
29180  tmp_ele_pt = 0;
29181  }
29182 
29183  // Re-start
29184  repeated = false;
29185 
29186  } // for (e < nel_in_region)
29187 
29188  // Add on the number of elements in the boundary with the
29189  // current region
29190  nel += nel_in_region;
29191 
29192  // Add on the number of repeated elements
29193  n_repeated_ele += nel_repeated_in_region;
29194 
29195  } // if (nel_in_region > 0)
29196 
29197  } // for (rr < n_regions)
29198 
29199  } // if (n_regions > 1)
29200  // Otherwise it's just the normal boundary functions
29201  else
29202  {
29203  // Assign the number of boundary elements
29204  nel = this->nboundary_element(b);
29205 
29206  // Only bother to do anything else, if there are elements
29207  if (nel > 0)
29208  {
29209  // Flag that activates when a repeated face element is found,
29210  // possibly because we are dealing with an internal boundary
29211  bool repeated = false;
29212 
29213  // Loop over the bulk elements adjacent to boundary b
29214  for (unsigned e = 0; e < nel; e++)
29215  {
29216  // Get pointer to the bulk element that is adjacent to boundary b
29217  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
29218 
29219 #ifdef OOMPH_HAS_MPI
29220  // In a distributed mesh only work with nonhalo elements
29221  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
29222  {
29223  // Increase the number of repeated elements
29224  n_repeated_ele++;
29225  // Go for the next element
29226  continue;
29227  }
29228 #endif
29229 
29230  // Find the index of the face of element e along boundary b
29231  int face_index = this->face_index_at_boundary(b, e);
29232 
29233  // Before adding the new element we need to be sure that the
29234  // edge that this element represent has not been already added
29235  FiniteElement* tmp_ele_pt =
29236  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
29237 
29238  // Number of nodes in the face element
29239  const unsigned n_nodes = tmp_ele_pt->nnode();
29240 
29241  std::pair<Node*, Node*> tmp_pair = std::make_pair(
29242  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
29243 
29244  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
29245  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
29246 
29247  // Search for repeated nodes
29248  unsigned n_done_nodes = done_nodes_pt.size();
29249  for (unsigned l = 0; l < n_done_nodes; l++)
29250  {
29251  if (tmp_pair == done_nodes_pt[l] ||
29252  tmp_pair_inverse == done_nodes_pt[l])
29253  {
29254  n_repeated_ele++;
29255  repeated = true;
29256  break;
29257  }
29258 
29259  } // for (l < n_done_nodes)
29260 
29261  // Create new face element
29262  if (!repeated)
29263  {
29264  // Add the pair of nodes (edge) to the node dones
29265  done_nodes_pt.push_back(tmp_pair);
29266  // Add the face element to the storage
29267  face_el_pt.push_back(tmp_ele_pt);
29268  }
29269  else
29270  {
29271  // Free the repeated bulk element!!
29272  delete tmp_ele_pt;
29273  tmp_ele_pt = 0;
29274  }
29275 
29276  // Re-start
29277  repeated = false;
29278 
29279  } // for (e < nel)
29280 
29281  } // if (nel > 0)
29282 
29283  } // else if (n_regions > 1)
29284 
29285  // Substract the repeated elements
29286  nel -= n_repeated_ele;
29287 
29288 #ifdef PARANOID
29289  if (nel != face_el_pt.size())
29290  {
29291  std::ostringstream error_message;
29292  error_message
29293  << "The independet counting of face elements (" << nel << ") for "
29294  << "boundary (" << b << ") is different\n"
29295  << "from the real number of face elements in the container ("
29296  << face_el_pt.size() << ")\n";
29297  throw OomphLibError(
29298  error_message.str(),
29299  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29300  OOMPH_EXCEPTION_LOCATION);
29301  }
29302 #endif
29303 
29304  // Only bother to do anything else, if there are elements
29305  if (nel > 0)
29306  {
29307  // Assign the number of nonhalo face elements
29308  const unsigned nnon_halo_face_elements = nel;
29309 
29310  // The vector of list to store the "segments" that compound the
29311  // boundary (segments may appear only in a distributed mesh)
29312  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
29313 
29314  // Number of already sorted face elements (only nonhalo face
29315  // elements for a distributed mesh)
29316  unsigned nsorted_face_elements = 0;
29317 
29318  // Keep track of who's done (in a distributed mesh this apply to
29319  // nonhalo only)
29320  std::map<FiniteElement*, bool> done_ele;
29321 
29322  // Keep track of which element is inverted (in distributed mesh
29323  // the elements may be inverted with respect to the segment they
29324  // belong)
29325  std::map<FiniteElement*, bool> is_inverted;
29326 
29327  // Iterate until all possible segments have been created. In a non
29328  // distributed mesh there is only one segment which defines the
29329  // complete boundary
29330  while (nsorted_face_elements < nnon_halo_face_elements)
29331  {
29332  // The ordered list of face elements (in a distributed mesh a
29333  // collection of continuous face elements define a segment)
29334  std::list<FiniteElement*> sorted_el_pt;
29335 
29336 #ifdef PARANOID
29337  // Select an initial element for the segment
29338  bool found_initial_face_element = false;
29339 #endif
29340 
29341  FiniteElement* ele_face_pt = 0;
29342 
29343  unsigned iface = 0;
29344 #ifdef OOMPH_HAS_MPI
29345  if (this->is_mesh_distributed())
29346  {
29347  for (iface = 0; iface < nel; iface++)
29348  {
29349  ele_face_pt = face_el_pt[iface];
29350  // If not done then take it as initial face element
29351  if (!done_ele[ele_face_pt])
29352  {
29353 #ifdef PARANOID
29354  // Set the flag to indicate the initial element was
29355  // found
29356  found_initial_face_element = true;
29357 #endif
29358  // Increase the number of sorted face elements
29359  nsorted_face_elements++;
29360  // Set the index to the next face element
29361  iface++;
29362  // Add the face element in the container
29363  sorted_el_pt.push_back(ele_face_pt);
29364  // Mark as done
29365  done_ele[ele_face_pt] = true;
29366  break;
29367  } // if (!done_el[ele_face_pt])
29368  } // for (iface < nel)
29369  } // if (this->is_mesh_distributed())
29370  else
29371  {
29372 #endif // #ifdef OOMPH_HAS_MPI
29373 
29374  // When the mesh is not distributed just take the first
29375  // element and put it in the ordered list
29376  ele_face_pt = face_el_pt[0];
29377 #ifdef PARANOID
29378  // Set the flag to indicate the initial element was found
29379  found_initial_face_element = true;
29380 #endif
29381  // Increase the number of sorted face elements
29382  nsorted_face_elements++;
29383  // Set the index to the next face element
29384  iface = 1;
29385  // Add the face element in the container
29386  sorted_el_pt.push_back(ele_face_pt);
29387  // Mark as done
29388  done_ele[ele_face_pt] = true;
29389 #ifdef OOMPH_HAS_MPI
29390  } // else if (this->is_mesh_distributed())
29391 #endif
29392 
29393 #ifdef PARANOID
29394  if (!found_initial_face_element)
29395  {
29396  std::ostringstream error_message;
29397  error_message << "Could not find an initial face element for the "
29398  "current segment\n";
29399  throw OomphLibError(
29400  error_message.str(),
29401  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29402  OOMPH_EXCEPTION_LOCATION);
29403  }
29404 #endif
29405 
29406  // Number of nodes in the face element
29407  const unsigned nnod = ele_face_pt->nnode();
29408 
29409  // Left and rightmost nodes (the left and right nodes of the
29410  // current face element)
29411  Node* left_node_pt = ele_face_pt->node_pt(0);
29412  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29413 
29414  // Continue iterating if a new face element has been added to
29415  // the list
29416  bool face_element_added = false;
29417 
29418  // While a new face element has been added to the set of sorted
29419  // face elements continue iterating
29420  do
29421  {
29422  // Start from the next face element since we have already
29423  // added the previous one as the initial face element (any
29424  // previous face element had to be added on previous
29425  // iterations)
29426  for (unsigned iiface = iface; iiface < nel; iiface++)
29427  {
29428  // Re-start flag
29429  face_element_added = false;
29430 
29431  // Get the candidate element
29432  ele_face_pt = face_el_pt[iiface];
29433 
29434  // Check that the candidate element has not been done and is
29435  // not a halo element
29436  if (!done_ele[ele_face_pt])
29437  {
29438  // Get the left and right nodes of the current element
29439  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29440  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29441 
29442  // New element fits at the left of segment and is not inverted
29443  if (left_node_pt == local_right_node_pt)
29444  {
29445  left_node_pt = local_left_node_pt;
29446  sorted_el_pt.push_front(ele_face_pt);
29447  is_inverted[ele_face_pt] = false;
29448  face_element_added = true;
29449  }
29450  // New element fits at the left of segment and is inverted
29451  else if (left_node_pt == local_left_node_pt)
29452  {
29453  left_node_pt = local_right_node_pt;
29454  sorted_el_pt.push_front(ele_face_pt);
29455  is_inverted[ele_face_pt] = true;
29456  face_element_added = true;
29457  }
29458  // New element fits on the right of segment and is not inverted
29459  else if (right_node_pt == local_left_node_pt)
29460  {
29461  right_node_pt = local_right_node_pt;
29462  sorted_el_pt.push_back(ele_face_pt);
29463  is_inverted[ele_face_pt] = false;
29464  face_element_added = true;
29465  }
29466  // New element fits on the right of segment and is inverted
29467  else if (right_node_pt == local_right_node_pt)
29468  {
29469  right_node_pt = local_left_node_pt;
29470  sorted_el_pt.push_back(ele_face_pt);
29471  is_inverted[ele_face_pt] = true;
29472  face_element_added = true;
29473  }
29474 
29475  if (face_element_added)
29476  {
29477  // Mark the face element as done
29478  done_ele[ele_face_pt] = true;
29479  nsorted_face_elements++;
29480  break;
29481  }
29482 
29483  } // if (!done_el[ele_face_pt])
29484 
29485  } // for (iiface<nnon_halo_face_element)
29486 
29487  } while (face_element_added &&
29488  (nsorted_face_elements < nnon_halo_face_elements));
29489 
29490  // Store the created segment in the vector of segments
29491  segment_sorted_ele_pt.push_back(sorted_el_pt);
29492 
29493  } // while(nsorted_face_elements < nnon_halo_face_elements);
29494 
29495  // The number of boundary segments in this processor
29496  const unsigned nsegments = segment_sorted_ele_pt.size();
29497 
29498 #ifdef PARANOID
29499  if (nnon_halo_face_elements > 0 && nsegments == 0)
29500  {
29501  std::ostringstream error_message;
29502  error_message
29503  << "The number of segments is zero, but the number of nonhalo\n"
29504  << "elements is: (" << nnon_halo_face_elements << ")\n";
29505  throw OomphLibError(
29506  error_message.str(),
29507  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29508  OOMPH_EXCEPTION_LOCATION);
29509  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29510 #endif
29511 
29512  // Go through all the segments, visit each face element in order
29513  // and get the nodes based that represent the boundary segment
29514 
29515  // Resize the container to store the nodes with the required
29516  // number of segments
29517  tmp_segment_nodes.resize(nsegments);
29518 
29519  for (unsigned is = 0; is < nsegments; is++)
29520  {
29521 #ifdef PARANOID
29522  if (segment_sorted_ele_pt[is].size() == 0)
29523  {
29524  std::ostringstream error_message;
29525  error_message << "The (" << is << ")-th segment has no elements\n";
29526  throw OomphLibError(
29527  error_message.str(),
29528  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29529  OOMPH_EXCEPTION_LOCATION);
29530  } // if (segment_sorted_ele_pt[is].size() == 0)
29531 #endif
29532 
29533  // Get access to the first element on the segment
29534  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29535 
29536  // Number of nodes
29537  const unsigned nnod = first_ele_pt->nnode();
29538 
29539  // Get the first node of the current segment
29540  Node* first_node_pt = first_ele_pt->node_pt(0);
29541  if (is_inverted[first_ele_pt])
29542  {
29543  first_node_pt = first_ele_pt->node_pt(nnod - 1);
29544  }
29545 
29546  // Add the node to the corresponding segment
29547  tmp_segment_nodes[is].push_back(first_node_pt);
29548 
29549  // Now loop over face elements in order to get the nodes
29550  for (std::list<FiniteElement*>::iterator it =
29551  segment_sorted_ele_pt[is].begin();
29552  it != segment_sorted_ele_pt[is].end();
29553  it++)
29554  {
29555  // Get element
29556  FiniteElement* ele_pt = *it;
29557 
29558  // The last node pointer
29559  Node* last_node_pt = 0;
29560 
29561  // Get the last node
29562  if (!is_inverted[ele_pt])
29563  {
29564  last_node_pt = ele_pt->node_pt(nnod - 1);
29565  }
29566  else
29567  {
29568  last_node_pt = ele_pt->node_pt(0);
29569  }
29570 
29571  // Add the node to the corresponding segment
29572  tmp_segment_nodes[is].push_back(last_node_pt);
29573 
29574  } // iterator over the elements in the segment
29575 
29576  } // for (is < nsegments)
29577 
29578  } // for (if (nel > 0))
29579 
29580  // Free memory allocation
29581  for (unsigned e = 0; e < nel; e++)
29582  {
29583  delete face_el_pt[e];
29584  face_el_pt[e] = 0;
29585  } // for (e < nel)
29586  }
29587 
29588  //======================================================================
29589  /// Adapt problem based on specified elemental error estimates
29590  /// This function implement serial and parallel mesh adaptation, the
29591  /// sections for parallel mesh adaptation are clearly identified by
29592  /// checking whether the mesh is distributed or not
29593  //======================================================================
29594  template<class ELEMENT>
29595  void RefineableTriangleMesh<ELEMENT>::adapt(const Vector<double>& elem_error)
29596  {
29597  double t_start_overall = TimingHelpers::timer();
29598 
29599  // ==============================================================
29600  // BEGIN: Compute target areas
29601  // ==============================================================
29602 
29603  // Get refinement targets
29604  Vector<double> target_area(elem_error.size());
29605  double min_angle = compute_area_target(elem_error, target_area);
29606 
29607  // Post-process to allow only quantised target areas
29608  // in an attempt to more closely mimick the structured
29609  // case and limit the diffusion of small elements.
29610  bool quantised_areas = true;
29611  if (quantised_areas)
29612  {
29613  unsigned n = target_area.size();
29614  double total_area = 0;
29615  // If the mesh is distributed then we need to get the contribution
29616  // of all processors to compute the total areas
29617  // ------------------------------------------
29618  // DISTRIBUTED MESH: BEGIN
29619  // ------------------------------------------
29620 #ifdef OOMPH_HAS_MPI
29621  if (this->is_mesh_distributed())
29622  {
29623  // When working in parallel we get the total area from the sum
29624  // of the the sub-areas of all the meshes
29625  double sub_area = 0.0;
29626 
29627  // Only add the area of nonhalo elements
29628  for (unsigned e = 0; e < n; e++)
29629  {
29630  // Get the pointer to the element
29631  FiniteElement* ele_pt = this->finite_element_pt(e);
29632  if (!ele_pt->is_halo())
29633  {
29634  sub_area += ele_pt->size();
29635  }
29636  } // for (e<n)
29637 
29638  // Get the communicator of the mesh
29639  OomphCommunicator* comm_pt = this->communicator_pt();
29640 
29641  // Get the total area
29642  MPI_Allreduce(
29643  &sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM, comm_pt->mpi_comm());
29644  }
29645  else
29646  {
29647  for (unsigned e = 0; e < n; e++)
29648  {
29649  total_area += this->finite_element_pt(e)->size();
29650  }
29651  }
29652  // ------------------------------------------
29653  // DISTRIBUTED MESH: END
29654  // ------------------------------------------
29655 #else // #ifdef OOMPH_HAS_MPI
29656  for (unsigned e = 0; e < n; e++)
29657  {
29658  total_area += this->finite_element_pt(e)->size();
29659  }
29660 #endif // #ifdef OOMPH_HAS_MPI
29661 
29662  for (unsigned e = 0; e < n; e++)
29663  {
29664  unsigned level =
29665  unsigned(ceil(log(target_area[e] / total_area) / log(1.0 / 3.0))) - 1;
29666  double new_target_area = total_area * pow(1.0 / 3.0, int(level));
29667  target_area[e] = new_target_area;
29668  }
29669  }
29670 
29671  // std::ofstream tmp;
29672  // tmp.open((Global_string_for_annotation::
29673  // String[0]+"overall_target_areas"+
29674  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29675 
29676  // Get maximum target area
29677  unsigned n = target_area.size();
29678  double max_area = 0.0;
29679  double min_area = DBL_MAX;
29680  for (unsigned e = 0; e < n; e++)
29681  {
29682  if (target_area[e] > max_area) max_area = target_area[e];
29683  if (target_area[e] < min_area) min_area = target_area[e];
29684 
29685  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29686  // finite_element_pt(e)->node_pt(1)->x(0)+
29687  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29688  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29689  // finite_element_pt(e)->node_pt(1)->x(1)+
29690  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29691  // << target_area[e] << " "
29692  // << finite_element_pt(e)->size() << " "
29693  // << elem_error[e] << " " << std::endl;
29694  }
29695 
29696  // tmp.close();
29697 
29698  oomph_info << "Maximum target area: " << max_area << std::endl;
29699  oomph_info << "Minimum target area: " << min_area << std::endl;
29700  oomph_info << "Number of elements to be refined: " << this->Nrefined
29701  << std::endl;
29702  oomph_info << "Number of elements to be unrefined: " << this->Nunrefined
29703  << std::endl;
29704  oomph_info << "Min. angle: " << min_angle << std::endl;
29705 
29706  double orig_max_area, orig_min_area;
29707  this->max_and_min_element_size(orig_max_area, orig_min_area);
29708  oomph_info << "Max./min. element size in original mesh: " << orig_max_area
29709  << " " << orig_min_area << std::endl;
29710 
29711  // ==============================================================
29712  // END: Compute target areas
29713  // ==============================================================
29714 
29715  // Check if boundaries need to be updated (regardless of
29716  // requirements of bulk error estimator) but don't do anything!
29717  bool check_only = true;
29718  bool outer_boundary_update_necessary = false;
29719  bool inner_boundary_update_necessary = false;
29720  bool inner_open_boundary_update_necessary = false;
29721 
29722  // Get the number of outer boundaries and check if they require
29723  // update
29724  const unsigned nouter = this->Outer_boundary_pt.size();
29725 
29726  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29727  {
29728  // loop over the outer boundaries
29729  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29730  {
29731  outer_boundary_update_necessary = this->update_polygon_using_face_mesh(
29732  this->Outer_boundary_pt[i_outer], check_only);
29733  // Break the loop if at least one needs updating
29734  if (outer_boundary_update_necessary) break;
29735  }
29736 
29737  // Do not waste time if we already know that it is necessary an update
29738  // on the boundary representation
29739  if (!outer_boundary_update_necessary)
29740  {
29741  // Check if we need to generate a new 1D mesh representation of
29742  // the inner hole boundaries
29743  const unsigned nhole = this->Internal_polygon_pt.size();
29744  Vector<Vector<double>> internal_point_coord(nhole);
29745  inner_boundary_update_necessary =
29746  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29747  check_only);
29748 
29749  // If there was not necessary a change even on the internal closed
29750  // curve then finally check for the open curves as well
29751  if (!inner_boundary_update_necessary)
29752  {
29753  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29754  // loop over the open polylines
29755  for (unsigned i = 0; i < n_open_polyline; i++)
29756  {
29757  inner_open_boundary_update_necessary =
29758  this->update_open_curve_using_face_mesh(
29759  this->Internal_open_curve_pt[i], check_only);
29760  // If at least one needs modification then break the for loop
29761  if (inner_open_boundary_update_necessary) break;
29762  }
29763  }
29764  }
29765  }
29766 
29767  // Flag to indicate whether we need to adapt or not (for parallel
29768  // mesh adaptation only)
29769  int adapt_all = 0;
29770  // ------------------------------------------
29771  // DISTRIBUTED MESH: BEGIN
29772  // ------------------------------------------
29773 #ifdef OOMPH_HAS_MPI
29774  // When working in distributed meshes we need to ensure that all the
29775  // processors take part on the adaptation process. If at least one
29776  // of the processors requires adaptation then all processor take
29777  // part on the adaptation process.
29778  int adapt_this_processor = 0;
29779  if (this->is_mesh_distributed())
29780  {
29781  // Do this processor requires adaptation?
29782  if ((Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29783  (min_angle < min_permitted_angle()) ||
29784  (outer_boundary_update_necessary) ||
29785  (inner_boundary_update_necessary) ||
29786  (inner_open_boundary_update_necessary))
29787  {
29788  adapt_this_processor = 1;
29789  }
29790 
29791  // Get the communicator of the mesh
29792  OomphCommunicator* comm_pt = this->communicator_pt();
29793 
29794  // Verify if at least one processor needs mesh adaptation
29795  MPI_Allreduce(&adapt_this_processor,
29796  &adapt_all,
29797  1,
29798  MPI_INT,
29799  MPI_SUM,
29800  comm_pt->mpi_comm());
29801  }
29802 #endif
29803  // ------------------------------------------
29804  // DISTRIBUTED MESH: END
29805  // ------------------------------------------
29806 
29807  // Should we bother to adapt?
29808  if ((Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29809  (min_angle < min_permitted_angle()) ||
29810  (outer_boundary_update_necessary) ||
29811  (inner_boundary_update_necessary) ||
29812  (inner_open_boundary_update_necessary) || (adapt_all))
29813  {
29814  if (!((Nrefined > 0) || (Nunrefined > max_keep_unrefined())))
29815  {
29816  if ((outer_boundary_update_necessary) ||
29817  (inner_boundary_update_necessary) ||
29818  (inner_open_boundary_update_necessary))
29819  {
29820  oomph_info
29821  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29822  << "representation; setting Nrefined to number of elements.\n"
29823  << "outer_boundary_update_necessary : "
29824  << outer_boundary_update_necessary << "\n"
29825  << "inner_boundary_update_necessary : "
29826  << inner_boundary_update_necessary << "\n"
29827  << "inner_open_boundary_update_necessary: "
29828  << inner_open_boundary_update_necessary << "\n";
29829  Nrefined = nelement();
29830  }
29831  else
29832  {
29833  oomph_info << "Mesh regeneration triggered by min angle criterion;\n"
29834  << "setting Nrefined to number of elements.\n";
29835  Nrefined = nelement();
29836  }
29837  }
29838 
29839  // ------------------------------------------
29840  // DISTRIBUTED MESH: BEGIN
29841  // ------------------------------------------
29842 #ifdef OOMPH_HAS_MPI
29843  else if (this->is_mesh_distributed() && adapt_this_processor == 0 &&
29844  adapt_all > 0)
29845  {
29846  oomph_info << "Mesh regeneration triggered by (" << adapt_all
29847  << ") processor(s) "
29848  << "that require(s)\n adaptation\n";
29849  }
29850 #endif
29851  // ------------------------------------------
29852  // DISTRIBUTED MESH: END
29853  // ------------------------------------------
29854 
29855  // ==============================================================
29856  // BEGIN: Updating of boundaries representation (unrefinement and
29857  // refinement of polylines)
29858  // ==============================================================
29859 
29860  // Add the initial and final vertices of the polylines that
29861  // present connections to a list of non-delete-able vertices. The
29862  // vertices where the connections are performed cannot be deleted
29863  add_vertices_for_non_deletion();
29864 
29865  // ------------------------------------------
29866  // DISTRIBUTED MESH: BEGIN
29867  // ------------------------------------------
29868 #ifdef OOMPH_HAS_MPI
29869  // Synchronise connections for shared boundaries among
29870  // processors. This is required since one of the processor may noy
29871  // know that some of its shared boundaries have connections, thus
29872  // the vertices receiving the connections cannot be deleted
29873  if (this->is_mesh_distributed())
29874  {
29875  synchronize_shared_boundary_connections();
29876  }
29877 #endif // #ifdef OOMPH_HAS_MPI
29878  // ------------------------------------------
29879  // DISTRIBUTED MESH: END
29880  // ------------------------------------------
29881 
29882  // Are we allowing automatic insertion of vertices on boundaries?
29883  // If YES then Triangle automatically insert points along
29884  // boundaries, if NOT, then points are inserted along the
29885  // boundaries based on the target areas of boundary elements. When
29886  // the mesh is distributed the automatic insertion of vertices by
29887  // Triangle along the boundaries is not allowed
29888  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29889  {
29890  // Generate a new 1D mesh representation of the inner hole boundaries
29891  unsigned nhole = this->Internal_polygon_pt.size();
29892  Vector<Vector<double>> internal_point_coord(nhole);
29893  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29894 
29895  // Update the representation of the outer boundary
29896  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29897  {
29898  this->update_polygon_using_face_mesh(
29899  this->Outer_boundary_pt[i_outer]);
29900  }
29901 
29902  // After updating outer and internal closed boundaries it is also
29903  // necessary to update internal boundaries.
29904  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29905  for (unsigned i = 0; i < n_open_polyline; i++)
29906  {
29907  this->update_open_curve_using_face_mesh(
29908  this->Internal_open_curve_pt[i]);
29909  }
29910  }
29911  else
29912  {
29913  // Update the representation of the internal boundaries using
29914  // the element's target area
29915 
29916  // Get the number of interal polygons
29917  const unsigned ninternal = this->Internal_polygon_pt.size();
29918  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29919  {
29920  this->update_polygon_using_elements_area(
29921  this->Internal_polygon_pt[i_internal], target_area);
29922  }
29923 
29924  // Update the representation of the outer boundaries using the
29925  // element's target area
29926  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29927  {
29928  this->update_polygon_using_elements_area(
29929  this->Outer_boundary_pt[i_outer], target_area);
29930  }
29931 
29932  // Update the representation of the internal open boundaries
29933  // using the element's target areas
29934  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29935  for (unsigned i = 0; i < n_open_polyline; i++)
29936  {
29937  this->update_open_curve_using_elements_area(
29938  this->Internal_open_curve_pt[i], target_area);
29939  }
29940 
29941  // ------------------------------------------
29942  // DISTRIBUTED MESH: BEGIN
29943  // ------------------------------------------
29944 
29945  // When working with a distributed mesh we require to update the
29946  // boundary representation of the shared boundaries, this is
29947  // based on the target areas of the elements adjaced to the
29948  // shared boundaries
29949 #ifdef OOMPH_HAS_MPI
29950  // Update shared boundaries if the mesh is distributed
29951  if (this->is_mesh_distributed())
29952  {
29953  // Get the rank of the current processor
29954  const unsigned my_rank = this->communicator_pt()->my_rank();
29955 
29956  // Get the number of shared curves
29957  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29958  // Loop over the shared curves in the current processor
29959  for (unsigned nc = 0; nc < n_curves; nc++)
29960  {
29961  // Update the shared polyline
29962  this->update_shared_curve_using_elements_area(
29963  this->Shared_boundary_polyline_pt[my_rank][nc], // shared_curve,
29964  target_area);
29965  }
29966 
29967  } // if (this->is_mesh_distributed())
29968 #endif
29969 
29970  // ------------------------------------------
29971  // DISTRIBUTED MESH: END
29972  // ------------------------------------------
29973 
29974  } // else if
29975  // (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29976 
29977  // ==============================================================
29978  // END: Updating of boundaries representation (unrefinement and
29979  // refinement of polylines)
29980  // ==============================================================
29981 
29982  // ==============================================================
29983  // BEGIN: Reset boundary coordinates for boundaries with no
29984  // associated GeomObject
29985  // ==============================================================
29986 
29987  // If there is not a geometric object associated with the boundary
29988  // then reset the boundary coordinates so that the lengths are
29989  // consistent in the new mesh and the old mesh.
29990  const unsigned n_boundary = this->nboundary();
29991 
29992  const double t_start_first_stage_segments_connectivity =
29993  TimingHelpers::timer();
29994 
29995  // ------------------------------------------
29996  // DISTRIBUTED MESH: BEGIN
29997  // ------------------------------------------
29998 #ifdef OOMPH_HAS_MPI
29999  // Clear storage for assignment of initial zeta values for
30000  // boundaries
30001  if (this->is_mesh_distributed())
30002  {
30003  this->Assigned_segments_initial_zeta_values.clear();
30004  }
30005 #endif // #ifdef OOMPH_HAS_MPI
30006  // ------------------------------------------
30007  // DISTRIBUTED MESH: END
30008  // ------------------------------------------
30009 
30010  // Loop over the boundaries to assign boundary coordinates
30011  for (unsigned b = 0; b < n_boundary; ++b)
30012  {
30013  // ------------------------------------------
30014  // DISTRIBUTED MESH: BEGIN
30015  // ------------------------------------------
30016 #ifdef OOMPH_HAS_MPI
30017  if (this->is_mesh_distributed())
30018  {
30019  // In a distributed mesh, the boundaries may have been split
30020  // across processors during the distribution process, thus we
30021  // need to compute the connectivity among the segments of the
30022  // boundary to correctly assign its boundary coordinates
30023  this->compute_boundary_segments_connectivity_and_initial_zeta_values(
30024  b);
30025  }
30026 #endif
30027  // ------------------------------------------
30028  // DISTRIBUTED MESH: END
30029  // ------------------------------------------
30030 
30031  // Does the boundary has an associated GeomObject
30032  if (this->boundary_geom_object_pt(b) == 0)
30033  {
30034  this->template setup_boundary_coordinates<ELEMENT>(b);
30035  }
30036 
30037  // ------------------------------------------
30038  // DISTRIBUTED MESH: BEGIN
30039  // ------------------------------------------
30040 #ifdef OOMPH_HAS_MPI
30041  if (this->is_mesh_distributed())
30042  {
30043  // Synchronise boundary coordinates for internal open curves,
30044  // also establish the boundary coordinates for the nodes on
30045  // the corners of elements not on the boundary
30046  this->synchronize_boundary_coordinates(b);
30047  }
30048 #endif
30049  // ------------------------------------------
30050  // DISTRIBUTED MESH: END
30051  // ------------------------------------------
30052 
30053  } // for (b<n_boundary)
30054 
30055  const double t_total_first_stage_segments_connectivity =
30056  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
30057 
30058  // ==============================================================
30059  // END: Reset boundary coordinates for boundaries with no
30060  // associated GeomObject
30061  // ==============================================================
30062 
30063  // ------------------------------------------
30064  // DISTRIBUTED MESH: BEGIN
30065  // ------------------------------------------
30066 #ifdef OOMPH_HAS_MPI
30067  // ==============================================================
30068  // BEGIN: Create the new representation of the domain by joining
30069  // the original boundaries and the shared boundaries.
30070  // ==============================================================
30071 
30072  // Storage for the new temporary polygons "closed" by the shared
30073  // boundaries
30074  Vector<TriangleMeshPolygon*> tmp_outer_polygons_pt;
30075 
30076  // Storage for the new temporary open curves, could be the
30077  // original open curves or "chunks" of the original open curves
30078  // not overlapped by shared boundaries
30079  Vector<TriangleMeshOpenCurve*> tmp_open_curves_pt;
30080 
30081  if (this->is_mesh_distributed())
30082  {
30083  // Create the new polygons and open curves with help of the
30084  // original polylines and shared polylines
30085  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
30086  tmp_open_curves_pt);
30087 
30088  // Create the connections of the temporary domain representations
30089  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
30090  tmp_open_curves_pt);
30091  }
30092  // ==============================================================
30093  // END: Create the new representation of the domain by joining
30094  // the original boundaries and the shared boundaries.
30095  // ==============================================================
30096 #endif
30097  // ------------------------------------------
30098  // DISTRIBUTED MESH: END
30099  // ------------------------------------------
30100 
30101  // Re-establish polylines' connections. The boundary
30102  // representation has changed (new polylines), therefore we need
30103  // to update the connection information
30104  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
30105  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
30106  restore_boundary_connections(resume_initial_connection_polyline_pt,
30107  resume_final_connection_polyline_pt);
30108 
30109  // Update the region information by setting the coordinates from the
30110  // centroid of the first element in each region (which should allow
30111  // automatic updates when the regions deform)
30112  {
30113  unsigned n_region = this->nregion();
30114  if (n_region > 1)
30115  {
30116  for (std::map<unsigned, Vector<double>>::iterator it =
30117  this->Regions_coordinates.begin();
30118  it != this->Regions_coordinates.end();
30119  ++it)
30120  {
30121  // Storage for the approximate centroid
30122  Vector<double> centroid(2, 0.0);
30123 
30124  // Get the region id
30125  unsigned region_id = it->first;
30126 
30127  // Report information
30128  oomph_info << "Region " << region_id << ": " << it->second[0] << " "
30129  << it->second[1] << " ";
30130 
30131  // Check that there is at least one element in the region
30132  unsigned n_region_element = this->nregion_element(region_id);
30133  if (n_region_element > 0)
30134  {
30135  // Cache pointer to the first element
30136  FiniteElement* const elem_pt =
30137  this->region_element_pt(region_id, 0);
30138 
30139  // Loop over the corners of the triangle and average
30140  for (unsigned n = 0; n < 3; n++)
30141  {
30142  Node* const nod_pt = elem_pt->node_pt(n);
30143  for (unsigned i = 0; i < 2; i++)
30144  {
30145  centroid[i] += nod_pt->x(i);
30146  }
30147  }
30148  for (unsigned i = 0; i < 2; i++)
30149  {
30150  centroid[i] /= 3;
30151  }
30152  // Now we have the centroid set it
30153  it->second = centroid;
30154 
30155  oomph_info << " , " << it->second[0] << " " << it->second[1]
30156  << std::endl;
30157  } // end of case when there is at least one element
30158 
30159  } // loop over regions coordinates
30160 
30161  } // if(n_region > 1)
30162 
30163  } // Updating region info.
30164 
30165  // ==============================================================
30166  // BEGIN: Create background mesh
30167  // ==============================================================
30168 
30169  // Are we dealing with a solid mesh?
30170  SolidMesh* solid_mesh_pt = dynamic_cast<SolidMesh*>(this);
30171 
30172  // Build temporary uniform background mesh
30173  //----------------------------------------
30174  // with area set by maximum required area
30175  //---------------------------------------
30176  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt = 0;
30177 
30178  // The storage for the new temporary boundaries representation to
30179  // create the background mesh
30180  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
30181  Vector<TriangleMeshClosedCurve*> hole_pt;
30182  Vector<TriangleMeshOpenCurve*> open_curves_pt;
30183 
30184 #ifdef OOMPH_HAS_MPI
30185  if (!this->is_mesh_distributed())
30186 #endif
30187  {
30188  // Copy the outer boundaries
30189  closed_curve_pt.resize(nouter);
30190  for (unsigned i = 0; i < nouter; i++)
30191  {
30192  closed_curve_pt[i] = this->Outer_boundary_pt[i];
30193  }
30194 
30195  // Copy the internal closed boundaries (may be holes)
30196  const unsigned n_holes = this->Internal_polygon_pt.size();
30197  hole_pt.resize(n_holes);
30198  for (unsigned i = 0; i < n_holes; i++)
30199  {
30200  hole_pt[i] = this->Internal_polygon_pt[i];
30201  }
30202 
30203  // Copy the internal open curves
30204  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
30205  open_curves_pt.resize(n_open_curves);
30206  for (unsigned i = 0; i < n_open_curves; i++)
30207  {
30208  open_curves_pt[i] = this->Internal_open_curve_pt[i];
30209  }
30210  }
30211  // ------------------------------------------
30212  // DISTRIBUTED MESH: BEGIN
30213  // ------------------------------------------
30214 #ifdef OOMPH_HAS_MPI
30215  else
30216  {
30217  // Copy the new representation of the outer/internal closed
30218  // boundaries
30219  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
30220  closed_curve_pt.resize(n_tmp_outer);
30221  for (unsigned i = 0; i < n_tmp_outer; i++)
30222  {
30223  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
30224  }
30225 
30226  // Copy the new representation of the internal open curves
30227  const unsigned n_open_curves = tmp_open_curves_pt.size();
30228  open_curves_pt.resize(n_open_curves);
30229  for (unsigned i = 0; i < n_open_curves; i++)
30230  {
30231  open_curves_pt[i] = tmp_open_curves_pt[i];
30232  }
30233  }
30234 #endif
30235  // ------------------------------------------
30236  // DISTRIBUTED MESH: END
30237  // ------------------------------------------
30238 
30239  // ----------------------------------------------------------------
30240  // Gather all the information and use the TriangleMeshParameters
30241  // object which help us on the manage of all TriangleMesh object's
30242  // information
30243 
30244  // Create the TriangleMeshParameters objects with the outer boundary
30245  // as the only one parameter
30246  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
30247 
30248  // Pass information about the holes
30249  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
30250 
30251  // Pass information about the internal open boundaries
30252  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
30253 
30254  // Set the element area
30255  triangle_mesh_parameters.element_area() = max_area;
30256 
30257  // Pass information about the extra holes (not defined with closed
30258  // boundaries)
30259  triangle_mesh_parameters.extra_holes_coordinates() =
30260  this->Extra_holes_coordinates;
30261 
30262  // Pass information about regions
30263  triangle_mesh_parameters.regions_coordinates() =
30264  this->Regions_coordinates;
30265 
30266  // Pass information about the using of regions
30267  if (this->Use_attributes)
30268  {
30269  triangle_mesh_parameters.enable_use_attributes();
30270  }
30271 
30272  // Pass information about allowing the creation of new points
30273  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30274  {
30275  triangle_mesh_parameters
30277  }
30278 
30279  // When the mesh is distributed we need to create a distributed
30280  // background mesh
30281 #ifdef OOMPH_HAS_MPI
30282  if (this->is_mesh_distributed())
30283  {
30284  // Mark the mesh to be created as distributed by passing a
30285  // pointer to the communicator
30286  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30287  }
30288 #endif
30289 
30290  // ----------------------------------------------------------
30291  // Build the background mesh using Triangle
30292  // ----------------------------------------------------------
30293  const double t_start_building_background_mesh = TimingHelpers::timer();
30294 
30295  if (solid_mesh_pt != 0)
30296  {
30297  tmp_new_mesh_pt = new RefineableSolidTriangleMesh<ELEMENT>(
30298  triangle_mesh_parameters, this->Time_stepper_pt);
30299  }
30300  else
30301  {
30302  tmp_new_mesh_pt = new RefineableTriangleMesh<ELEMENT>(
30303  triangle_mesh_parameters, this->Time_stepper_pt);
30304  }
30305 
30306  if (Print_timings_level_adaptation > 2)
30307  {
30308  oomph_info << "CPU for building background mesh: "
30309  << TimingHelpers::timer() - t_start_building_background_mesh
30310  << std::endl;
30311  }
30312 
30313  // Pass the info. regarding the maximum and minimum element size
30314  // from the old mesh to the background mesh
30315  const double this_max_element_size = this->max_element_size();
30316  const double this_min_element_size = this->min_element_size();
30317  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30318  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30319 
30320  // ... also copy the minimum permitted angle
30321  const double this_min_permitted_angle = this->min_permitted_angle();
30322  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30323 
30324  // ------------------------------------------
30325  // DISTRIBUTED MESH: BEGIN
30326  // ------------------------------------------
30327 #ifdef OOMPH_HAS_MPI
30328  // If the mesh is distributed we need to pass and set the
30329  // information of internal boundaries overlaped by shared
30330  // boundaries
30331  if (this->is_mesh_distributed())
30332  {
30333  // Check if necessary to fill boundary elements for those
30334  // internal boundaries that overlap shared boundaries
30335  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30336  {
30337  // Copy the data structures that indicates which shared
30338  // boundaries are part of an internal boundary
30339  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30340  this->shared_boundary_overlaps_internal_boundary();
30341 
30342  // Copy the data structure that indicates which are the shared
30343  // boundaries in each processor
30344  tmp_new_mesh_pt->shared_boundaries_ids() =
30345  this->shared_boundaries_ids();
30346 
30347  // Fill the structures for the boundary elements and face indexes
30348  // of the boundary elements
30349  tmp_new_mesh_pt
30351 
30352  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30353 
30354  } // if (this->is_mesh_distributed())
30355 #endif // #ifdef OOMPH_HAS_MPI
30356  // ------------------------------------------
30357  // DISTRIBUTED MESH: END
30358  // ------------------------------------------
30359 
30360  // Snap to curvilinear boundaries (some code duplication as this
30361  // is repeated below but helper function would take so many
30362  // arguments that it's nearly as messy...
30363 
30364  // Pass the boundary geometric objects to the new mesh
30365  tmp_new_mesh_pt->boundary_geom_object_pt() =
30366  this->boundary_geom_object_pt();
30367 
30368  // Reset the boundary coordinates if there is
30369  // a geometric object associated with the boundary
30370  tmp_new_mesh_pt->boundary_coordinate_limits() =
30371  this->boundary_coordinate_limits();
30372 
30373  const double t_start_second_stage_segments_connectivity =
30374  TimingHelpers::timer();
30375 
30376  for (unsigned b = 0; b < n_boundary; b++)
30377  {
30378  // ------------------------------------------
30379  // DISTRIBUTED MESH: BEGIN
30380  // ------------------------------------------
30381 #ifdef OOMPH_HAS_MPI
30382  if (this->is_mesh_distributed())
30383  {
30384  // Identify the segments of the new mesh with the ones of the
30385  // original mesh
30386  tmp_new_mesh_pt
30388  this);
30389  }
30390 #endif
30391  // ------------------------------------------
30392  // DISTRIBUTED MESH: END
30393  // ------------------------------------------
30394 
30395  // Setup boundary coordinates for boundaries with GeomObject
30396  // associated
30397  if (tmp_new_mesh_pt->boundary_geom_object_pt(b) != 0)
30398  {
30399  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30400  }
30401  }
30402 
30403  const double t_total_second_stage_segments_connectivity =
30404  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30405 
30406  const double t_start_snap_nodes_bg_mesh = TimingHelpers::timer();
30407  // Move the nodes on the new boundary onto the old curvilinear
30408  // boundary. If the boundary is straight this will do precisely
30409  // nothing but will be somewhat inefficient
30410  for (unsigned b = 0; b < n_boundary; b++)
30411  {
30412  this->snap_nodes_onto_boundary(tmp_new_mesh_pt, b);
30413  }
30414 
30415  const double t_total_snap_nodes_bg_mesh =
30416  TimingHelpers::timer() - t_start_snap_nodes_bg_mesh;
30417 
30418  if (Print_timings_level_adaptation > 2)
30419  {
30420  oomph_info << "CPU for snapping nodes onto boundaries "
30421  << "(background mesh): " << t_total_snap_nodes_bg_mesh
30422  << std::endl;
30423  }
30424 
30425  // Update mesh further?
30426  if (Mesh_update_fct_pt != 0)
30427  {
30428  Mesh_update_fct_pt(tmp_new_mesh_pt);
30429  }
30430 
30431  // If we have a continuation problem
30432  // any problem in which the timestepper is a "generalisedtimestepper",
30433  // which will have been set by the problem, then ensure
30434  // all data in the new mesh has the appropriate timestepper
30435  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30436  {
30437  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30438  this->Time_stepper_pt);
30439  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30440  }*/
30441 
30442 
30443  // tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30444  // this->output("existing_mesh.dat");
30445 
30446  // ==============================================================
30447  // END: Create background mesh
30448  // ==============================================================
30449 
30450  // ==============================================================
30451  // BEGIN: Transferring of target areas and creation of new mesh
30452  // ==============================================================
30453 
30454  // Get the TriangulateIO object associated with that mesh
30455  TriangulateIO tmp_new_triangulateio =
30456  tmp_new_mesh_pt->triangulateio_representation();
30457  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30458 
30459  // If the mesh is a solid mesh then do the mapping based on the
30460  // Eulerian coordinates
30461  bool use_eulerian_coords = false;
30462  if (solid_mesh_pt != 0)
30463  {
30464  use_eulerian_coords = true;
30465  }
30466 
30467 
30468 #ifdef OOMPH_HAS_CGAL
30469 
30470  // Make cgal-based bin
30471  CGALSamplePointContainerParameters cgal_params(this);
30472  if (use_eulerian_coords)
30473  {
30474  cgal_params.enable_use_eulerian_coordinates_during_setup();
30475  }
30476  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(&cgal_params);
30477 
30478 #else
30479 
30480  // Make nonrefineable bin
30481  NonRefineableBinArrayParameters params(this);
30482  if (use_eulerian_coords)
30483  {
30484  params.enable_use_eulerian_coordinates_during_setup();
30485  }
30486  Vector<unsigned> bin_dim(2);
30487  bin_dim[0] = Nbin_x_for_area_transfer;
30488  bin_dim[1] = Nbin_y_for_area_transfer;
30489  params.dimensions_of_bin_array() = bin_dim;
30490  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(&params);
30491 
30492 #endif
30493 
30494  // Set up a map from pointer to element to its number
30495  // in the mesh
30496  std::map<GeneralisedElement*, unsigned> element_number;
30497  unsigned nelem = this->nelement();
30498  for (unsigned e = 0; e < nelem; e++)
30499  {
30500  element_number[this->element_pt(e)] = e;
30501  }
30502 
30503 #ifndef OOMPH_HAS_CGAL
30504 
30505  // Create a vector to store the min target area of each bin (at
30506  // this stage the number of bins should not be that large, so it
30507  // should be safe to build a vector for the total number of bins)
30508  Vector<double> bin_min_target_area;
30509 
30510  // Get pointer to sample point container
30511  NonRefineableBinArray* bin_array_pt =
30512  dynamic_cast<NonRefineableBinArray*>(
30513  mesh_geom_obj_pt->sample_point_container_pt());
30514  if (bin_array_pt == 0)
30515  {
30516  throw OomphLibError(
30517  "Sample point container has to be NonRefineableBinArray",
30518  OOMPH_CURRENT_FUNCTION,
30519  OOMPH_EXCEPTION_LOCATION);
30520  }
30521 
30522  {
30523  unsigned n_bin = 0;
30524  unsigned max_n_entry = 0;
30525  unsigned min_n_entry = UINT_MAX;
30526  unsigned tot_n_entry = 0;
30527  unsigned n_empty = 0;
30528  bin_array_pt->get_fill_stats(
30529  n_bin, max_n_entry, min_n_entry, tot_n_entry, n_empty);
30530 
30531  oomph_info << "Before bin diffusion:"
30532  << " nbin:(" << n_bin << ")"
30533  << " nempty:(" << n_empty << ")"
30534  << " min:(" << min_n_entry << ")"
30535  << " max:(" << max_n_entry << ")"
30536  << " average entries:("
30537  << double(tot_n_entry) / double(n_bin) << ")" << std::endl;
30538  }
30539 
30540  // Fill bin by diffusion
30541  double t0_bin_diff = TimingHelpers::timer();
30542  oomph_info << "Going into diffusion bit...\n";
30543  bin_array_pt->fill_bin_by_diffusion();
30544  oomph_info << "Back from diffusion bit...\n";
30545  oomph_info << "Time for bin diffusion: "
30546  << TimingHelpers::timer() - t0_bin_diff << std::endl;
30547 
30548  // Do some stats
30549  {
30550  unsigned n_bin = 0;
30551  unsigned max_n_entry = 0;
30552  unsigned min_n_entry = UINT_MAX;
30553  unsigned tot_n_entry = 0;
30554  unsigned n_empty = 0;
30555  bin_array_pt->get_fill_stats(
30556  n_bin, max_n_entry, min_n_entry, tot_n_entry, n_empty);
30557 
30558  oomph_info << "After bin diffusion:"
30559  << " nbin:(" << n_bin << ")"
30560  << " nempty:(" << n_empty << ")"
30561  << " min:(" << min_n_entry << ")"
30562  << " max:(" << max_n_entry << ")"
30563  << " average entries:("
30564  << double(tot_n_entry) / double(n_bin) << ")" << std::endl;
30565  }
30566 
30567 
30568  // For each bin, compute the minimum of the target areas in the bin
30569 
30570  // Timing for map
30571  double t_total_map = 0.0;
30572 
30573  // Counter for map
30574  unsigned counter_map = 0;
30575 
30576  // Get access to the bins (we need access to the content of the
30577  // bins to compute the minimum of the target areas of the elements
30578  // in each bin)
30579  const std::map<unsigned,
30580  Vector<std::pair<FiniteElement*, Vector<double>>>>*
30581  bins_pt = bin_array_pt->get_all_bins_content();
30582 
30583  // Get the number of bins
30584  const unsigned n_bin = bins_pt->size();
30585 
30586  // Create a vector to store the min target area of each bin (at
30587  // this stage the number of bins should not be that large, so it
30588  // should be safe to build a vector for the total number of bins)
30589  bin_min_target_area.resize(n_bin);
30590  for (unsigned u = 0; u < n_bin; u++)
30591  {
30592  bin_min_target_area[u] = 0.0;
30593  }
30594  // loop over the bins, get their elements and compute the minimum
30595  // target area of all of them
30596  typedef std::map<
30597  unsigned,
30598  Vector<std::pair<FiniteElement*, Vector<double>>>>::const_iterator IT;
30599  for (IT it = bins_pt->begin(); it != bins_pt->end(); it++)
30600  {
30601  // The bin number
30602  unsigned ib = (*it).first;
30603 
30604  // Get the number of elements in the bin
30605  const unsigned n_ele_bin = (*it).second.size();
30606 
30607  // loop over the elements in the bin
30608  for (unsigned ee = 0; ee < n_ele_bin; ee++)
30609  {
30610  // Get ee-th element (in currrent mesh) in ib-th bin
30611  GeneralisedElement* ele_pt = (*it).second[ee].first;
30612  double t_map = TimingHelpers::timer();
30613  const unsigned ele_number = element_number[ele_pt];
30614  t_total_map += TimingHelpers::timer() - t_map;
30615 
30616  // Increase the number of calls to map
30617  counter_map++;
30618 
30619  // Go for smallest target area of any element in this bin to
30620  // force "one level" of refinement (the one-level-ness is
30621  // enforced below by limiting the actual reduction in area
30622  if (bin_min_target_area[ib] != 0)
30623  {
30624  bin_min_target_area[ib] =
30625  std::min(bin_min_target_area[ib], target_area[ele_number]);
30626  }
30627  else
30628  {
30629  bin_min_target_area[ib] = target_area[ele_number];
30630  }
30631 
30632  } // for (ee<n_ele_bin)
30633 
30634  } // for (it!=bins.end())
30635 
30636  oomph_info << "CPU for map[counter=" << counter_map
30637  << "]: " << t_total_map << std::endl;
30638 
30639 
30640  // Optional output for debugging (keep it around!)
30641  const bool output_bins = false;
30642  if (output_bins)
30643  {
30644  unsigned length = bin_min_target_area.size();
30645  for (unsigned u = 0; u < length; u++)
30646  {
30647  oomph_info << "Bin n" << u
30648  << ",target area: " << bin_min_target_area[u] << std::endl;
30649  }
30650  }
30651 
30652 #endif
30653 
30654 
30655  // Now start iterating to refine mesh recursively
30656  //-----------------------------------------------
30657  bool done = false;
30658  unsigned iter = 0;
30659 #ifdef OOMPH_HAS_MPI
30660  // The number of elements that require (un)refinement
30661  unsigned n_ele_need_refinement = 0;
30662 #endif
30663 
30664  // The timing for the third stage of segments connectivity
30665  double t_total_third_stage_segments_connectivity = 0.0;
30666 
30667  // The timing for the transfering target areas
30668  double t_total_transfer_target_areas = 0.0;
30669 
30670  // The timing for the copying of target areas
30671  double t_total_limit_target_areas = 0.0;
30672 
30673  // The timing to create the new mesh
30674  double t_total_create_new_adapted_mesh = 0.0;
30675 
30676  // The timing for the snapping of the nodes on the new meshes
30677  double t_total_snap_nodes = 0.0;
30678 
30679  // The timing to check whether other processors need to adapt
30680  double t_total_wait_other_processors = 0.0;
30681  double t_iter = TimingHelpers::timer();
30682  while (!done)
30683  {
30684  // Accept by default but overwrite if things go wrong below
30685  done = true;
30686 
30687  double t_start_transfer_target_areas = TimingHelpers::timer();
30688  double t0_loop_int_pts = TimingHelpers::timer();
30689 
30690  // Loop over elements in new (tmp) mesh and visit all
30691  // its integration points. Check where it's located in the bin
30692  // structure of the current mesh and pass the target area
30693  // to the new element
30694  nelem = tmp_new_mesh_pt->nelement();
30695 
30696  // Store the target areas for elements in the temporary
30697  // TriangulateIO mesh
30698  Vector<double> new_transferred_target_area(nelem, 0.0);
30699  for (unsigned e = 0; e < nelem; e++)
30700  { // start loop el
30701  ELEMENT* el_pt =
30702  dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30703  unsigned nint = el_pt->integral_pt()->nweight();
30704  for (unsigned ipt = 0; ipt < nint; ipt++)
30705  {
30706  // Get the coordinate of current point
30707  Vector<double> s(2);
30708  for (unsigned i = 0; i < 2; i++)
30709  {
30710  s[i] = el_pt->integral_pt()->knot(ipt, i);
30711  }
30712 
30713  Vector<double> x(2);
30714  el_pt->interpolated_x(s, x);
30715 
30716 #if OOMPH_HAS_CGAL
30717 
30718  // Try the five nearest sample points for Newton search
30719  // then just settle on the nearest one
30720  GeomObject* geom_obj_pt = 0;
30721  unsigned max_sample_points =
30722  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30723  dynamic_cast<CGALSamplePointContainer*>(
30724  mesh_geom_obj_pt->sample_point_container_pt())
30725  ->limited_locate_zeta(x, max_sample_points, geom_obj_pt, s);
30726 #ifdef PARANOID
30727  if (geom_obj_pt == 0)
30728  {
30729  std::stringstream error_message;
30730  error_message << "Limited locate zeta failed for zeta = [ "
30731  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30732  throw OomphLibError(error_message.str(),
30733  OOMPH_CURRENT_FUNCTION,
30734  OOMPH_EXCEPTION_LOCATION);
30735  }
30736  else
30737  {
30738 #endif
30739  FiniteElement* fe_pt = dynamic_cast<FiniteElement*>(geom_obj_pt);
30740 #ifdef PARANOID
30741  if (fe_pt == 0)
30742  {
30743  std::stringstream error_message;
30744  error_message << "Cast to FE for GeomObject returned by "
30745  "limited locate zeta failed for zeta = [ "
30746  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30747  throw OomphLibError(error_message.str(),
30748  OOMPH_CURRENT_FUNCTION,
30749  OOMPH_EXCEPTION_LOCATION);
30750  }
30751  else
30752  {
30753 #endif
30754  // What's the target area of the element that contains this
30755  // point
30756  double tg_area = target_area[element_number[fe_pt]];
30757 
30758  // Go for smallest target area over all integration
30759  // points in new element
30760  // to force "one level" of refinement (the one-level-ness
30761  // is enforced below by limiting the actual reduction in
30762  // area
30763  if (new_transferred_target_area[e] != 0)
30764  {
30765  new_transferred_target_area[e] =
30766  std::min(new_transferred_target_area[e], tg_area);
30767  }
30768  else
30769  {
30770  new_transferred_target_area[e] = tg_area;
30771  }
30772 #ifdef PARANOID
30773  }
30774  }
30775 #endif
30776 
30777 #else
30778 
30779  // Find the bin that contains that point and its contents
30780  int bin_number = 0;
30781  bin_array_pt->get_bin(x, bin_number);
30782 
30783  // Did we find it?
30784  if (bin_number < 0)
30785  {
30786  // Not even within bin boundaries... odd
30787  std::stringstream error_message;
30788  error_message << "Very odd -- we're looking for a point[ " << x[0]
30789  << " " << x[1] << " ] that's not even \n"
30790  << "located within the bin boundaries.\n";
30791  throw OomphLibError(error_message.str(),
30792  "RefineableTriangleMesh::adapt()",
30793  OOMPH_EXCEPTION_LOCATION);
30794  } // if (bin_number<0)
30795  else
30796  {
30797  // Go for smallest target area of any element in this bin
30798  // to force "one level" of refinement (the one-level-ness
30799  // is enforced below by limiting the actual reduction in
30800  // area
30801  if (new_transferred_target_area[e] != 0)
30802  {
30803  new_transferred_target_area[e] =
30804  std::min(new_transferred_target_area[e],
30805  bin_min_target_area[bin_number]);
30806  }
30807  else
30808  {
30809  new_transferred_target_area[e] =
30810  bin_min_target_area[bin_number];
30811  }
30812  }
30813 
30814 #endif
30815 
30816  } // for (ipt<nint)
30817 
30818  } // for (e<nelem)
30819 
30820 
30821  // do some output (keep it alive!)
30822  const bool output_target_areas = false;
30823  if (output_target_areas)
30824  {
30825  unsigned length = new_transferred_target_area.size();
30826  for (unsigned u = 0; u < length; u++)
30827  {
30828  oomph_info << "Element" << u
30829  << ",target area: " << new_transferred_target_area[u]
30830  << std::endl;
30831  }
30832  }
30833  oomph_info << "Time for loop over integration points in new mesh: "
30834  << TimingHelpers::timer() - t0_loop_int_pts << std::endl;
30835 
30836 
30837  // {
30838  // tmp.open((Global_string_for_annotation::
30839  // String[0]+"binned_target_areas"+
30840  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30841 
30842  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > >
30843  // bin_content=
30844  // mesh_geom_obj_pt->bin_content();
30845  // unsigned nbin=bin_content.size();
30846  // for (unsigned b=0;b<nbin;b++)
30847  // {
30848  // unsigned nentry=bin_content[b].size();
30849  // for (unsigned entry=0;entry<nentry;entry++)
30850  // {
30851  // FiniteElement* el_pt=bin_content[b][entry].first;
30852  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30853  // Vector<double> s=bin_content[b][entry].second;
30854  // Vector<double> x(2);
30855  // el_pt->interpolated_x(s,x);
30856  // unsigned e_current=element_number[gen_el_pt];
30857  // tmp << x[0] << " " << x[1] << " "
30858  // << target_area[e_current] << " "
30859  // << el_pt->size() << " "
30860  // << std::endl;
30861  // }
30862  // }
30863  // tmp.close();
30864  // }
30865 
30866  const double t_sub_total_transfer_target_areas =
30867  TimingHelpers::timer() - t_start_transfer_target_areas;
30868 
30869  if (Print_timings_level_adaptation > 2)
30870  {
30871  // Get the number of elements in the old mesh (this)
30872  const unsigned n_element = this->nelement();
30873  // Get the number of elements in the background mesh
30874  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30875 
30876  oomph_info << "CPU for transfer of target areas "
30877  << "[n_ele_old_mesh=" << n_element
30878  << ", n_ele_background_mesh=" << n_element_background
30879  << "] (iter " << iter
30880  << "): " << t_sub_total_transfer_target_areas << std::endl;
30881  }
30882 
30883  // Add the timing for tranfer of target areas
30884  t_total_transfer_target_areas += t_sub_total_transfer_target_areas;
30885 
30886  // // Output mesh
30887  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30888  // StringConversion::to_string(iter)+".dat").c_str());
30889 
30890  // tmp.open((Global_string_for_annotation::
30891  // String[0]+"target_areas_intermediate_mesh_iter"+
30892  // StringConversion::to_string(iter)+"_"+
30893  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30894 
30895  const double t_start_limit_target_areas = TimingHelpers::timer();
30896 
30897  // Now copy into target area for temporary mesh but limit to
30898  // the equivalent of one sub-division per iteration
30899 #ifdef OOMPH_HAS_MPI
30900  unsigned n_ele_need_refinement_iter = 0;
30901 #endif
30902 
30903 
30904  // Don't delete! Keep these around for debugging
30905  // ofstream tmp_mesh_file;
30906  // tmp_mesh_file.open("tmp_mesh_file.dat");
30907  // tmp_new_mesh_pt->output(tmp_mesh_file);
30908  // tmp_mesh_file.close();
30909  // ofstream target_areas_file;
30910  // target_areas_file.open("target_areas_file.dat");
30911 
30912  const unsigned nel_new = tmp_new_mesh_pt->nelement();
30913  Vector<double> new_target_area(nel_new);
30914  for (unsigned e = 0; e < nel_new; e++)
30915  {
30916  // The finite element
30917  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30918 
30919  // Transferred target area
30920  const double new_area = new_transferred_target_area[e];
30921  if (new_area <= 0.0)
30922  {
30923  std::ostringstream error_stream;
30924  error_stream
30925  << "This shouldn't happen! Element whose centroid is at "
30926  << (f_ele_pt->node_pt(0)->x(0) + f_ele_pt->node_pt(1)->x(0) +
30927  f_ele_pt->node_pt(2)->x(0)) /
30928  3.0
30929  << " "
30930  << (f_ele_pt->node_pt(0)->x(1) + f_ele_pt->node_pt(1)->x(1) +
30931  f_ele_pt->node_pt(2)->x(1)) /
30932  3.0
30933  << " "
30934  << " has no target area assigned\n";
30935  throw OomphLibError(error_stream.str(),
30936  OOMPH_CURRENT_FUNCTION,
30937  OOMPH_EXCEPTION_LOCATION);
30938  }
30939  else
30940  {
30941  // Limit target area to the equivalent of uniform refinement
30942  // during this stage of the iteration
30943  new_target_area[e] = new_area;
30944  if (new_target_area[e] < f_ele_pt->size() / 3.0)
30945  {
30946  new_target_area[e] = f_ele_pt->size() / 3.0;
30947 
30948  // We'll need to give it another go later
30949  done = false;
30950  }
30951 
30952  // Don't delete! Keep around for debugging
30953  // target_areas_file
30954  // << (f_ele_pt->node_pt(0)->x(0)+
30955  // f_ele_pt->node_pt(1)->x(0)+
30956  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30957  // << (f_ele_pt->node_pt(0)->x(1)+
30958  // f_ele_pt->node_pt(1)->x(1)+
30959  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30960  // << new_area << " "
30961  // << new_target_area[e] << std::endl;
30962 
30963 
30964 #ifdef OOMPH_HAS_MPI
30965  // Keep track of the elements that require (un)refinement
30966  n_ele_need_refinement_iter++;
30967 #endif
30968 
30969  } // else if (new_area <= 0.0)
30970 
30971  } // for (e < nel_new)
30972 
30973 
30974  // Don't delete! Keep around for debugging
30975  // target_areas_file.close();
30976 
30977  const double t_sub_total_limit_target_areas =
30978  TimingHelpers::timer() - t_start_limit_target_areas;
30979 
30980  // Add the timing for copying target areas
30981  t_total_limit_target_areas += t_sub_total_limit_target_areas;
30982 
30983  if (Print_timings_level_adaptation > 2)
30984  {
30985  // Get the number of elements in the old mesh (this)
30986  const unsigned n_element = this->nelement();
30987  // Get the number of elements in the background mesh
30988  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30989 
30990  oomph_info << "CPU for limiting target areas "
30991  << "[n_ele_old_mesh=" << n_element
30992  << ", n_ele_background_mesh=" << n_element_background
30993  << "] (iter " << iter
30994  << "): " << t_sub_total_limit_target_areas << std::endl;
30995  }
30996 
30997  if (done)
30998  {
30999  oomph_info
31000  << "All area adjustments accommodated by max. permitted area"
31001  << " reduction \n";
31002  }
31003  else
31004  {
31005  oomph_info << "NOT all area adjustments accommodated by max. "
31006  << "permitted area reduction \n";
31007  }
31008 
31009  // tmp.close();
31010  // pause("doced binned_target_areas.dat and intermediate mesh targets");
31011 
31012  // Now create the new mesh from TriangulateIO structure
31013  //-----------------------------------------------------
31014  // associated with uniform background mesh and the
31015  //------------------------------------------------
31016  // associated target element sizes.
31017  //---------------------------------
31018 
31019  const double t_start_create_new_adapted_mesh = TimingHelpers::timer();
31020 
31021  // Solid mesh?
31022  if (solid_mesh_pt != 0)
31023  {
31024  new_mesh_pt = new RefineableSolidTriangleMesh<ELEMENT>(
31025  new_target_area,
31026  tmp_new_triangulateio,
31027  this->Time_stepper_pt,
31028  this->Use_attributes,
31029  this->Allow_automatic_creation_of_vertices_on_boundaries,
31030  this->communicator_pt());
31031  }
31032  // No solid mesh
31033  else
31034  {
31035  new_mesh_pt = new RefineableTriangleMesh<ELEMENT>(
31036  new_target_area,
31037  tmp_new_triangulateio,
31038  this->Time_stepper_pt,
31039  this->Use_attributes,
31040  this->Allow_automatic_creation_of_vertices_on_boundaries,
31041  this->communicator_pt());
31042  }
31043 
31044  // Sub-total to create new adapted mesh
31045  const double t_sub_total_create_new_adapted_mesh =
31046  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
31047 
31048  // Add the time to the total snap nodes time
31049  t_total_create_new_adapted_mesh += t_sub_total_create_new_adapted_mesh;
31050 
31051  if (Print_timings_level_adaptation > 2)
31052  {
31053  // Get the number of elements of the new adapted mesh
31054  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
31055 
31056  oomph_info << "CPU for creation of new adapted mesh "
31057  << t_sub_total_create_new_adapted_mesh
31058  << "[nele=" << n_element_new_adapted_mesh << "] (iter "
31059  << iter << "): " << t_sub_total_create_new_adapted_mesh
31060  << std::endl;
31061  }
31062 
31063 #ifdef OOMPH_HAS_MPI
31064  // ------------------------------------------
31065  // DISTRIBUTED MESH: BEGIN
31066  // ------------------------------------------
31067 
31068  // This section is only required if we are dealing with
31069  // distributed meshes, otherwise there are not shared boundaries
31070  // overlapping internal boundaries
31071 
31072  // Check if necessary to fill boundary elements for those internal
31073  // boundaries that overlap shared boundaries
31074  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
31075  {
31076  // Copy the data structures that indicate which shared
31077  // boundaries are part of an internal boundary
31079  this->shared_boundary_overlaps_internal_boundary();
31080 
31081  // Copy the data structure that indicates which are the shared
31082  // boundaries in each processor
31083  new_mesh_pt->shared_boundaries_ids() = this->shared_boundaries_ids();
31084 
31085  // Fill the structures for the boundary elements and face indexes
31086  // of the boundary elements
31087  new_mesh_pt
31089  }
31090  // ------------------------------------------
31091  // DISTRIBUTED MESH: END
31092  // ------------------------------------------
31093 #endif // #ifdef OOMPH_HAS_MPI
31094 
31095  // Snap to curvilinear boundaries (some code duplication as this
31096  // is repeated below but helper function would take so many
31097  // arguments that it's nearly as messy...
31098 
31099  // Pass the boundary geometric objects to the new mesh
31100  new_mesh_pt->boundary_geom_object_pt() =
31101  this->boundary_geom_object_pt();
31102 
31103  // Reset the boundary coordinates if there is
31104  // a geometric object associated with the boundary
31105  new_mesh_pt->boundary_coordinate_limits() =
31106  this->boundary_coordinate_limits();
31107 
31108  const double t_start_third_stage_segments_connectivity =
31109  TimingHelpers::timer();
31110 
31111  for (unsigned b = 0; b < n_boundary; b++)
31112  {
31113  // ------------------------------------------
31114  // DISTRIBUTED MESH: BEGIN
31115  // ------------------------------------------
31116 
31117  // Before setting up boundary coordinates for the new mesh we
31118  // require to identify the segments with the old mesh to
31119  // assign initial zeta values
31120 #ifdef OOMPH_HAS_MPI
31121  if (this->is_mesh_distributed())
31122  {
31123  // Identify the segments of the new mesh with the ones of
31124  // the original mesh
31125  new_mesh_pt
31127  this);
31128  }
31129 #endif
31130  // ------------------------------------------
31131  // DISTRIBUTED MESH: END
31132  // ------------------------------------------
31133 
31134  // Setup boundary coordinates for boundaries with GeomObject
31135  // associated
31136  if (new_mesh_pt->boundary_geom_object_pt(b) != 0)
31137  {
31138  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
31139  }
31140  }
31141 
31142  t_total_third_stage_segments_connectivity +=
31143  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
31144 
31145  const double t_start_snap_nodes_new_mesh = TimingHelpers::timer();
31146  // Move the nodes on the new boundary onto the old curvilinear
31147  // boundary. If the boundary is straight this will do precisely
31148  // nothing but will be somewhat inefficient
31149  for (unsigned b = 0; b < n_boundary; b++)
31150  {
31151  this->snap_nodes_onto_boundary(new_mesh_pt, b);
31152  }
31153 
31154  const double t_sub_total_snap_nodes_new_mesh =
31155  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
31156 
31157  // Add the time to the total snap nodes time
31158  t_total_snap_nodes += t_sub_total_snap_nodes_new_mesh;
31159 
31160  if (Print_timings_level_adaptation > 2)
31161  {
31162  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
31163  << "(iter " << iter
31164  << "): " << t_sub_total_snap_nodes_new_mesh << std::endl;
31165  }
31166 
31167  // Update mesh further?
31168  if (Mesh_update_fct_pt != 0)
31169  {
31170  Mesh_update_fct_pt(new_mesh_pt);
31171  }
31172 
31173  // If we have a continuation problem
31174  // any problem in which the timestepper is a "generalisedtimestepper",
31175  // which will have been set by the problem, then ensure
31176  // all data in the new mesh has the appropriate timestepper
31177  if (dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
31178  {
31179  new_mesh_pt->set_nodal_and_elemental_time_stepper(
31180  this->Time_stepper_pt, false);
31181  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,
31182  false);
31183  }
31184 
31185  // Not done: get ready for another iteration
31186  iter++;
31187  delete tmp_new_mesh_pt;
31188 
31189 #ifdef OOMPH_HAS_MPI
31190  // Check whether the number of elements that need (un)refinement
31191  // from the previous iteration is the same, if that is the case
31192  // then we mark this processor as done
31193  if (n_ele_need_refinement_iter == n_ele_need_refinement)
31194  {
31195  done = true;
31196  }
31197  // Update the number of elements that require further
31198  // (un)refinement
31199  n_ele_need_refinement = n_ele_need_refinement_iter;
31200 #endif // #ifdef OOMPH_HAS_MPI
31201 
31202  // ------------------------------------------
31203  // DISTRIBUTED MESH: BEGIN
31204  // ------------------------------------------
31205 
31206  // We can only finish the iteration adaptation process if ALL
31207  // the involved processor are marked as done, otherwise, ALL
31208  // processor need to go for another iteration
31209 #ifdef OOMPH_HAS_MPI
31210  if (this->is_mesh_distributed())
31211  {
31212  // Time to check whether other processors have finish to adapt
31213  const double t_start_wait_other_processors = TimingHelpers::timer();
31214 
31215  // In case that the mesh is distributed it is necessary to
31216  // verify that no processor requires further refinement. If at
31217  // least one processor needs more refinement then all
31218  // processors need to go for another iteration to participate
31219  // in the communications
31220  unsigned this_processor_requires_another_iteration = 1;
31221 
31222  // Is this processor done?
31223  if (done)
31224  {
31225  this_processor_requires_another_iteration = 0;
31226  }
31227  int nproc_not_done = this_processor_requires_another_iteration;
31228  // Get the communicator of the mesh
31229  OomphCommunicator* comm_pt = this->communicator_pt();
31230  // Communicate with all procesoors to check whether we need to
31231  // re-iterate
31232  MPI_Allreduce(&this_processor_requires_another_iteration,
31233  &nproc_not_done,
31234  1,
31235  MPI_UNSIGNED,
31236  MPI_SUM,
31237  comm_pt->mpi_comm());
31238  // Are all processors done?
31239  if (nproc_not_done > 0)
31240  {
31241  oomph_info
31242  << "At least one processors requires further refinement. "
31243  << "Go for another iteration." << std::endl;
31244  done = false;
31245  }
31246 
31247  // Total to check whether other processors have finish to
31248  // adapt
31249  const double t_sub_total_wait_other_processors =
31250  TimingHelpers::timer() - t_start_wait_other_processors;
31251 
31252  // Add to the total timings to check whether other processors
31253  // need to adapt
31254  t_total_wait_other_processors += t_sub_total_wait_other_processors;
31255 
31256  if (Print_timings_level_adaptation > 2)
31257  {
31258  oomph_info << "CPU for waiting other processors "
31259  << "(iter " << iter
31260  << "): " << t_sub_total_wait_other_processors
31261  << std::endl;
31262  }
31263 
31264  } // if (this->is_mesh_distributed())
31265 #endif
31266  // ------------------------------------------
31267  // DISTRIBUTED MESH: END
31268  // ------------------------------------------
31269 
31270  if (!done)
31271  {
31272  oomph_info << "Going for another iteration. Current iteration ("
31273  << iter << ")" << std::endl;
31274 
31275  // Use the new mesh as the tmp mesh
31276  tmp_new_mesh_pt = new_mesh_pt;
31277  tmp_new_triangulateio = new_mesh_pt->triangulateio_representation();
31278  }
31279 
31280  } // end of iteration (while (!done))
31281 
31282  // Delete the temporary geometric object representation of the
31283  // current mesh
31284  delete mesh_geom_obj_pt;
31285 
31286  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31287  << TimingHelpers::timer() - t_iter << std::endl;
31288 
31289  if (Print_timings_level_adaptation > 1)
31290  {
31291  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31292  << t_total_create_new_adapted_mesh << std::endl;
31293 
31294  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31295  << t_total_limit_target_areas << std::endl;
31296 
31297  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31298  << t_total_transfer_target_areas << std::endl;
31299 
31300  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31301  << t_total_wait_other_processors << std::endl;
31302  }
31303 
31304  // ==============================================================
31305  // END: Transferring of target areas and creation of new mesh
31306  // ==============================================================
31307 
31308  // ==============================================================
31309  // BEGIN: Project solution from the old to the new mesh
31310  // ==============================================================
31311 
31312  // Check that the projection step is not disabled
31313  if (!Disable_projection)
31314  {
31315  // Take the time for the projection step
31316  double tt_start_projection = TimingHelpers::timer();
31317 
31318  // Print info. for tranfering target areas
31319  if (Print_timings_projection)
31320  {
31321  // Switch timings and stats on
31322  Multi_domain_functions::Doc_timings = true;
31323  Multi_domain_functions::Doc_stats = true;
31324  Multi_domain_functions::Doc_full_stats = true;
31325  }
31326 
31327  double t_proj = TimingHelpers::timer();
31328  oomph_info << "About to begin projection.\n";
31329 
31330  // Project current solution onto new mesh
31331  //---------------------------------------
31332  ProjectionProblem<ELEMENT>* project_problem_pt =
31333  new ProjectionProblem<ELEMENT>;
31334 
31335  // Projection requires to be enabled as distributed if working
31336  // with a distributed mesh
31337 #ifdef OOMPH_HAS_MPI
31338  if (this->is_mesh_distributed())
31339  {
31340  // ------------------------------------------
31341  // DISTRIBUTED MESH: BEGIN
31342  // ------------------------------------------
31343 
31344  // We need to back up the time stepper object since the
31345  // projection class creates a new one
31346  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31347 
31348  // Set the projection problem as distributed
31349  project_problem_pt->enable_problem_distributed();
31350 
31351  // Pass the time stepper to the projection problem (used when
31352  // setting multi_domain_interation)
31353  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31354 
31355  // Set the mesh used for the projection object
31356  project_problem_pt->mesh_pt() = new_mesh_pt;
31357  // project_problem_pt->disable_suppress_output_during_projection();
31358 
31359  // Use iterative solver for projection? By default, an iterative
31360  // solver is used for the projection stage
31361  if (!this->use_iterative_solver_for_projection())
31362  {
31363  project_problem_pt->disable_use_iterative_solver_for_projection();
31364  }
31365 
31366  // Do the projection
31367  project_problem_pt->project(this);
31368 
31369  // Reset the time stepper object (only affects distributed meshes)
31370  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31371 
31372  // ------------------------------------------
31373  // DISTRIBUTED MESH: END
31374  // ------------------------------------------
31375 
31376  } // if (this->is_mesh_distributed())
31377  else
31378 #endif // #ifdef OOMPH_HAS_MPI
31379  {
31380  // Set the mesh used for the projection object
31381  project_problem_pt->mesh_pt() = new_mesh_pt;
31382 
31383  // project_problem_pt->disable_suppress_output_during_projection();
31384 
31385  // Use iterative solver for projection? By default, an iterative
31386  // solver is used for the projection stage
31387  if (!this->use_iterative_solver_for_projection())
31388  {
31389  project_problem_pt->disable_use_iterative_solver_for_projection();
31390  }
31391 
31392  // Do the projection
31393  project_problem_pt->project(this);
31394  }
31395 
31396  // Reset printing info. for projection
31397  if (Print_timings_projection)
31398  {
31399  // Switch timings and stats off
31400  Multi_domain_functions::Doc_timings = false;
31401  Multi_domain_functions::Doc_stats = false;
31402  Multi_domain_functions::Doc_full_stats = false;
31403  }
31404 
31405  // Get the total time for projection
31406  const double tt_projection =
31407  TimingHelpers::timer() - tt_start_projection;
31408 
31409  if (Print_timings_level_adaptation > 1)
31410  {
31411  // Get the number of elements in the old mesh (this)
31412  const unsigned n_element = this->nelement();
31413  // Get the number of elements in the new mesh
31414  const unsigned n_element_new = new_mesh_pt->nelement();
31415  oomph_info << "CPU for projection (in mesh adaptation) "
31416  << "[n_ele_old_mesh=" << n_element
31417  << ", n_ele_new_mesh=" << n_element_new
31418  << "]: " << tt_projection << std::endl;
31419 
31420  // ------------------------------------------
31421  // DISTRIBUTED MESH: BEGIN
31422  // ------------------------------------------
31423 #ifdef OOMPH_HAS_MPI
31424  if (this->is_mesh_distributed())
31425  {
31426  // The maximum number of elements in the mesh (over all
31427  // processors)
31428  unsigned n_this_element_new = n_element_new;
31429  unsigned n_max_element_new_global = 0;
31430  // Get the maximum number of elements over all processors
31431  MPI_Reduce(&n_this_element_new,
31432  &n_max_element_new_global,
31433  1,
31434  MPI_UNSIGNED,
31435  MPI_MAX,
31436  0,
31437  this->communicator_pt()->mpi_comm());
31438 
31439  // The time for projection for this processor
31440  double tt_this_projection = tt_projection;
31441  double tt_global_min_projection = 0.0;
31442  double tt_global_max_projection = 0.0;
31443 
31444  // Get the minimum and maximum time for projection
31445  MPI_Reduce(&tt_this_projection,
31446  &tt_global_min_projection,
31447  1,
31448  MPI_DOUBLE,
31449  MPI_MIN,
31450  0,
31451  this->communicator_pt()->mpi_comm());
31452  MPI_Reduce(&tt_this_projection,
31453  &tt_global_max_projection,
31454  1,
31455  MPI_DOUBLE,
31456  MPI_MAX,
31457  0,
31458  this->communicator_pt()->mpi_comm());
31459 
31460  if (this->communicator_pt()->my_rank() == 0)
31461  {
31462  oomph_info << "CPU for projection global (MIN): "
31463  << tt_global_min_projection << std::endl;
31464  oomph_info << "CPU for projection global (MAX) "
31465  << "[n_max_ele_new_global=" << n_max_element_new_global
31466  << "]: " << tt_global_max_projection << std::endl;
31467 
31468  std::cerr << "CPU for projection global (MIN): "
31469  << tt_global_min_projection << std::endl;
31470  std::cerr << "CPU for projection global (MAX): "
31471  << "[n_max_ele_new_global=" << n_max_element_new_global
31472  << "]: " << tt_global_max_projection << std::endl;
31473  }
31474  }
31475 #endif // #ifdef OOMPH_HAS_MPI
31476  // ------------------------------------------
31477  // DISTRIBUTED MESH: END
31478  // ------------------------------------------
31479 
31480  } // if (Print_timings_level_adaptation>1)
31481 
31482  oomph_info << "CPU for projection of solution onto new mesh: "
31483  << TimingHelpers::timer() - t_proj << std::endl;
31484 
31485  // Delete the projection problem
31486  delete project_problem_pt;
31487 
31488  } // if (!Disable_projection)
31489  else
31490  {
31491  oomph_info << "Projection disabled! The new mesh will contain zeros"
31492  << std::endl;
31493  }
31494 
31495  // ==============================================================
31496  // END: Project solution from the old to the new mesh
31497  // ==============================================================
31498 
31499  double t_rest = TimingHelpers::timer();
31500 
31501  // Flush the old mesh
31502  unsigned nnod = nnode();
31503  for (unsigned j = nnod; j > 0; j--)
31504  {
31505  delete Node_pt[j - 1];
31506  Node_pt[j - 1] = 0;
31507  }
31508  unsigned nel = nelement();
31509  for (unsigned e = nel; e > 0; e--)
31510  {
31511  delete Element_pt[e - 1];
31512  Element_pt[e - 1] = 0;
31513  }
31514 
31515  // Now copy back to current mesh
31516  //------------------------------
31517  nnod = new_mesh_pt->nnode();
31518  Node_pt.resize(nnod);
31519  nel = new_mesh_pt->nelement();
31520  Element_pt.resize(nel);
31521  for (unsigned j = 0; j < nnod; j++)
31522  {
31523  Node_pt[j] = new_mesh_pt->node_pt(j);
31524  }
31525  for (unsigned e = 0; e < nel; e++)
31526  {
31527  Element_pt[e] = new_mesh_pt->element_pt(e);
31528  }
31529 
31530  // Copy the boundary elements information from the new mesh to the
31531  // original mesh
31532  unsigned nbound = 0;
31533 
31534 #ifdef OOMPH_HAS_MPI
31535  // If working with a distributed mesh we need to change the number
31536  // of boundaries so that shared boundaries information is also
31537  // copied from the old to the new mesh
31538  if (this->is_mesh_distributed())
31539  {
31540  // The boundaries to be copied include those new ones in the new
31541  // mesh (shared boundaries). This info. is required to
31542  // re-establish the halo/haloed scheme
31543  nbound = new_mesh_pt->nboundary();
31544  // After halo and haloed scheme has been re-established the
31545  // number of boundaries is changed to the original number of
31546  // boundaries
31547  }
31548  else
31549 #endif
31550  {
31551  // The original number of boundaries
31552  nbound = n_boundary;
31553  }
31554 
31555  Boundary_element_pt.resize(nbound);
31556  Face_index_at_boundary.resize(nbound);
31557  Boundary_node_pt.resize(nbound);
31558  for (unsigned b = 0; b < nbound; b++)
31559  {
31560  unsigned nel = new_mesh_pt->nboundary_element(b);
31561  Boundary_element_pt[b].resize(nel);
31562  Face_index_at_boundary[b].resize(nel);
31563  for (unsigned e = 0; e < nel; e++)
31564  {
31565  Boundary_element_pt[b][e] = new_mesh_pt->boundary_element_pt(b, e);
31566  Face_index_at_boundary[b][e] =
31567  new_mesh_pt->face_index_at_boundary(b, e);
31568  }
31569  unsigned nnod = new_mesh_pt->nboundary_node(b);
31570  Boundary_node_pt[b].resize(nnod);
31571  for (unsigned j = 0; j < nnod; j++)
31572  {
31573  Boundary_node_pt[b][j] = new_mesh_pt->boundary_node_pt(b, j);
31574  }
31575  }
31576 
31577  // Also copy over the new boundary and region information
31578  unsigned n_region = new_mesh_pt->nregion();
31579  // Only bother if we have regions
31580  if (n_region > 1)
31581  {
31582  // Deal with the region information first
31583  this->Region_attribute.resize(n_region);
31584  for (unsigned r = 0; r < n_region; r++)
31585  {
31586  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31587  // Get the region id
31588  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31589  // Find the number of elements in the region
31590  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31591  this->Region_element_pt[r_id].resize(n_region_element);
31592  for (unsigned e = 0; e < n_region_element; e++)
31593  {
31594  this->Region_element_pt[r_id][e] =
31595  new_mesh_pt->region_element_pt(r_id, e);
31596  }
31597  }
31598 
31599  // Now the boundary region information
31600  this->Boundary_region_element_pt.resize(nbound);
31601  this->Face_index_region_at_boundary.resize(nbound);
31602 
31603  // Now loop over the boundaries
31604  for (unsigned b = 0; b < nbound; ++b)
31605  {
31606  for (unsigned rr = 0; rr < n_region; rr++)
31607  {
31608  // The region id
31609  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31610 
31611  unsigned n_boundary_el_in_region =
31612  new_mesh_pt->nboundary_element_in_region(b, r);
31613 
31614  if (n_boundary_el_in_region > 0)
31615  {
31616  // Allocate storage in the map
31617  this->Boundary_region_element_pt[b][r].resize(
31618  n_boundary_el_in_region);
31619  this->Face_index_region_at_boundary[b][r].resize(
31620  n_boundary_el_in_region);
31621 
31622  // Copy over the information
31623  for (unsigned e = 0; e < n_boundary_el_in_region; ++e)
31624  {
31625  this->Boundary_region_element_pt[b][r][e] =
31626  new_mesh_pt->boundary_element_in_region_pt(b, r, e);
31627  this->Face_index_region_at_boundary[b][r][e] =
31628  new_mesh_pt->face_index_at_boundary_in_region(b, r, e);
31629  }
31630  }
31631  }
31632  } // End of loop over boundaries
31633 
31634  } // End of case when more than one region
31635 
31636  // ------------------------------------------
31637  // DISTRIBUTED MESH: BEGIN
31638  // ------------------------------------------
31639 
31640  // Re-generate halo(ed) information (only for distributed meshes)
31641 #ifdef OOMPH_HAS_MPI
31642  if (this->is_mesh_distributed())
31643  {
31644  // Delete halo(ed) information in the original mesh, the new
31645  // halo(ed) information is generated usign the info. of the new
31646  // mesh
31647  if (this->is_mesh_distributed())
31648  {
31649  this->Halo_node_pt.clear();
31650  this->Root_halo_element_pt.clear();
31651 
31652  this->Haloed_node_pt.clear();
31653  this->Root_haloed_element_pt.clear();
31654 
31655  this->External_halo_node_pt.clear();
31656  this->External_halo_element_pt.clear();
31657 
31658  this->External_haloed_node_pt.clear();
31659  this->External_haloed_element_pt.clear();
31660  }
31661 
31662  // Re-establish the shared boundary elements and nodes scheme
31663  // before re-establish halo(ed) information
31664  this->reset_shared_boundary_elements_and_nodes();
31665 
31666  // -------------------------------------------------------------
31667  // Remove shared boundary elements and nodes from original
31668  // boundary elements and boundary nodes containers. Shared
31669  // boundary elements and nodes are stored in a special
31670  // container.
31671 
31672  // Get the shared boundaries in this processor with any other
31673  // processor
31674  Vector<unsigned> my_rank_shared_boundaries_ids;
31675  this->shared_boundaries_in_this_processor(
31676  my_rank_shared_boundaries_ids);
31677 
31678  // Get the number of shared boundaries
31679  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31680  // Loop over the shared boundaries marked as original boundaries
31681  // in tmp_new_mesh
31682  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31683  {
31684  // Get the boundary id
31685  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31686  // Flush any previous relation of shared boundary elements
31687  // marked as original boundary elements in tmp_new_mesh
31688  this->Boundary_element_pt[shd_bnd_id].clear();
31689 
31690  // Get the number of nodes associated with the original
31691  // boundary in tmp_new_mesh that is a shared boundary
31692  const unsigned tmp_nnodes = this->nshared_boundary_node(shd_bnd_id);
31693  for (unsigned n = 0; n < tmp_nnodes; n++)
31694  {
31695  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31696  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31697  } // for (n < nnodes)
31698 
31699  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31700 
31701  // Re-set the number of boundaries to the original one
31702  this->set_nboundary(n_boundary);
31703 
31704  // Sort the nodes on the boundaries so that they have the same
31705  // order on all the boundaries
31706  this->sort_nodes_on_shared_boundaries();
31707 
31708  // Re-set the halo(ed) scheme
31709  this->reset_halo_haloed_scheme();
31710 
31711  // Set the correct number of segments for the boundaries with
31712  // geom objects associated
31713  for (unsigned b = 0; b < n_boundary; b++)
31714  {
31715  if (this->boundary_geom_object_pt(b) != 0)
31716  {
31717  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31718  this->set_nboundary_segment_node(b, nsegments);
31719  }
31720  }
31721 
31722  // Resume the connections in boundaries were it was suspended
31723  resume_boundary_connections(resume_initial_connection_polyline_pt,
31724  resume_final_connection_polyline_pt);
31725 
31726  } // if (this->is_mesh_distributed())
31727 
31728 #endif // #ifdef OOMPH_HAS_MPI
31729 
31730  // ------------------------------------------
31731  // DISTRIBUTED MESH: END
31732  // ------------------------------------------
31733 
31734  // Snap the newly created nodes onto any geometric objects
31735  this->snap_nodes_onto_geometric_objects();
31736 
31737  // Copy the IDs of the vertex nodes
31738  this->Oomph_vertex_nodes_id = new_mesh_pt->oomph_vertex_nodes_id();
31739 
31740  // Copy TriangulateIO representation
31741  TriangleHelper::clear_triangulateio(this->Triangulateio);
31742  bool quiet = true;
31743  this->Triangulateio =
31744  TriangleHelper::deep_copy_of_triangulateio_representation(
31745  new_mesh_pt->triangulateio_representation(), quiet);
31746 
31747  // Flush the mesh
31748  new_mesh_pt->flush_element_and_node_storage();
31749 
31750  // Delete the mesh
31751  delete new_mesh_pt;
31752 
31753  // Resume of timings
31754  if (Print_timings_level_adaptation > 2)
31755  {
31756  // Report timings related with setting boundary coordinates of
31757  // nodes on segments
31758  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31759  << t_total_first_stage_segments_connectivity << std::endl;
31760  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31761  << t_total_second_stage_segments_connectivity << std::endl;
31762  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31763  << t_total_third_stage_segments_connectivity << std::endl;
31764  }
31765 
31766  if (Print_timings_level_adaptation > 1)
31767  {
31768  const double t_total_segments_connectivity =
31769  t_total_first_stage_segments_connectivity +
31770  t_total_second_stage_segments_connectivity +
31771  t_total_third_stage_segments_connectivity;
31772 
31773  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31774  << t_total_segments_connectivity << std::endl;
31775 
31776  if (Print_timings_level_adaptation > 2)
31777  {
31778  // Report timings for snapping of nodes onto boundaries
31779  oomph_info << "CPU for snapping nodes onto boundaries "
31780  << "(new mesh): " << t_total_snap_nodes << std::endl;
31781  }
31782 
31783  t_total_snap_nodes += t_total_snap_nodes_bg_mesh;
31784  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31785  << t_total_snap_nodes << std::endl;
31786  }
31787 
31788  double max_area = 0.0;
31789  double min_area = 0.0;
31790 
31791  this->max_and_min_element_size(max_area, min_area);
31792  oomph_info << "Max/min element size in adapted mesh: " << max_area << " "
31793  << min_area << std::endl;
31794 
31795  oomph_info << "CPU time for final bits [sec]: "
31796  << TimingHelpers::timer() - t_rest << std::endl;
31797  }
31798  else
31799  {
31800  oomph_info << "Not enough benefit in adaptation.\n";
31801  Nrefined = 0;
31802  Nunrefined = 0;
31803  }
31804 
31805  double CPU_for_adaptation = TimingHelpers::timer() - t_start_overall;
31806  oomph_info << "CPU time for adaptation [sec]: " << CPU_for_adaptation
31807  << std::endl;
31808 
31809  // ------------------------------------------
31810  // DISTRIBUTED MESH: BEGIN
31811  // ------------------------------------------
31812 #ifdef OOMPH_HAS_MPI
31813  if (this->is_mesh_distributed())
31814  {
31815  // Get the communicator
31816  OomphCommunicator* comm_pt = this->communicator_pt();
31817  // Get the total number of processors to compute the average
31818  const unsigned n_proc = comm_pt->nproc();
31819  if (Print_timings_level_adaptation > 1 && n_proc > 1)
31820  {
31821  double global_min_CPU_for_adaptation = 0.0;
31822  double global_max_CPU_for_adaptation = 0.0;
31823  double global_average_CPU_for_adaptation = 0.0;
31824 
31825  // Get the maximum and minimum of the adaptation times
31826  MPI_Reduce(&CPU_for_adaptation,
31827  &global_min_CPU_for_adaptation,
31828  1,
31829  MPI_DOUBLE,
31830  MPI_MIN,
31831  0,
31832  comm_pt->mpi_comm());
31833  MPI_Reduce(&CPU_for_adaptation,
31834  &global_max_CPU_for_adaptation,
31835  1,
31836  MPI_DOUBLE,
31837  MPI_MAX,
31838  0,
31839  comm_pt->mpi_comm());
31840  MPI_Reduce(&CPU_for_adaptation,
31841  &global_average_CPU_for_adaptation,
31842  1,
31843  MPI_DOUBLE,
31844  MPI_SUM,
31845  0,
31846  comm_pt->mpi_comm());
31847 
31848  // Get the rank of the processor
31849  const unsigned my_rank = comm_pt->my_rank();
31850  if (my_rank == 0)
31851  {
31852  oomph_info << "CPU for adaptation (MIN): "
31853  << global_min_CPU_for_adaptation << std::endl;
31854  oomph_info << "CPU for adaptation (MAX): "
31855  << global_max_CPU_for_adaptation << std::endl;
31856  oomph_info << "CPU for adaptation (AVERAGE): "
31857  << global_average_CPU_for_adaptation / n_proc << std::endl;
31858  } // if (my_rank==0)
31859 
31860  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31861 
31862  } // if (this->is_mesh_distributed())
31863 
31864  // ------------------------------------------
31865  // DISTRIBUTED MESH: END
31866  // ------------------------------------------
31867 
31868 #endif // #ifdef OOMPH_HAS_MPI
31869  }
31870 
31871  //=========================================================================
31872  /// \ short Mark the vertices that are not allowed for deletion by
31873  /// the unrefienment/refinement polyline methods. In charge of
31874  /// filling the Boundary_connections_pt structure
31875  //=========================================================================
31876  template<class ELEMENT>
31878  {
31879  // Clear any previous information
31880  // Boundary_chunk_connections_pt.clear();
31881  Boundary_connections_pt.clear();
31882 
31883  // Loop over the boundaries in the domain (outer, internal -- closed
31884  // and open ---, and shared) and get the boundaries ids with
31885  // connections (have or receive)
31886 
31887  // Store the boundaries ids that have or receive connection
31888  std::set<unsigned> boundary_id_with_connections;
31889 
31890  // ------------------------------------------------------------------
31891  // Outer boundaries
31892  // ------------------------------------------------------------------
31893 
31894  // Get the number of outer boundaries (closed boundaries)
31895  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31896 
31897  // Loop over the outer boundaries
31898  for (unsigned i = 0; i < n_outer_boundaries; i++)
31899  {
31900  // Get a temporary polygon representation
31901  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31902  // Get the number of polylines associated to the current outer
31903  // boundary
31904  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31905  // Loop over the polylines
31906  for (unsigned p = 0; p < n_polyline; p++)
31907  {
31908  // Get a temporary representation of the polyline
31909  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
31910 
31911  // Is the initial vertex connected?
31912  if (tmp_polyline_pt->is_initial_vertex_connected())
31913  {
31914  // Get the boundary id of the current polyline
31915  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31916 
31917  // Include the boundary id to the set of boundaries with
31918  // connections
31919  boundary_id_with_connections.insert(bnd_id);
31920 
31921  // Boundary id to which the curve is connecte
31922  const unsigned dst_bnd_id =
31923  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31924 
31925  // Include the destination boundary id to the set of
31926  // boundaries with connections
31927  boundary_id_with_connections.insert(dst_bnd_id);
31928 
31929  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31930 
31931  // Is the final vertex connected?
31932  if (tmp_polyline_pt->is_final_vertex_connected())
31933  {
31934  // Get the boundary id of the current polyline
31935  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31936 
31937  // Include the boundary id to the set of boundaries with
31938  // connections
31939  boundary_id_with_connections.insert(bnd_id);
31940 
31941  // Boundary id to which the curve is connected
31942  const unsigned dst_bnd_id =
31943  tmp_polyline_pt->final_vertex_connected_bnd_id();
31944 
31945  // Include the destination boundary id to the set of
31946  // boundaries with connections
31947  boundary_id_with_connections.insert(dst_bnd_id);
31948 
31949  } // if (tmp_polyline_pt->is_final_vertex_connected())
31950 
31951  } // for (p < n_polyline)
31952 
31953  } // for (i < n_outer_boundaries)
31954 
31955  // ------------------------------------------------------------------
31956  // Internal boundaries
31957  // ------------------------------------------------------------------
31958 
31959  // Get the number of internal boundaries (closed boundaries)
31960  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31961 
31962  // Loop over the internal boundaries
31963  for (unsigned i = 0; i < n_internal_boundaries; i++)
31964  {
31965  // Get a temporary polygon representation
31966  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31967  // Get the number of polylines associated to the current internal
31968  // boundary
31969  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31970  // Loop over the polylines
31971  for (unsigned p = 0; p < n_polyline; p++)
31972  {
31973  // Get a temporary representation of the polyline
31974  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
31975 
31976  // Is the initial vertex connected?
31977  if (tmp_polyline_pt->is_initial_vertex_connected())
31978  {
31979  // Get the boundary id of the current polyline
31980  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31981 
31982  // Include the boundary id to the set of boundaries with
31983  // connections
31984  boundary_id_with_connections.insert(bnd_id);
31985 
31986  // Boundary id to which the curve is connecte
31987  const unsigned dst_bnd_id =
31988  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31989 
31990  // Include the destination boundary id to the set of
31991  // boundaries with connections
31992  boundary_id_with_connections.insert(dst_bnd_id);
31993 
31994  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31995 
31996  // Is the final vertex connected?
31997  if (tmp_polyline_pt->is_final_vertex_connected())
31998  {
31999  // Get the boundary id of the current polyline
32000  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32001 
32002  // Include the boundary id to the set of boundaries with
32003  // connections
32004  boundary_id_with_connections.insert(bnd_id);
32005 
32006  // Boundary id to which the curve is connected
32007  const unsigned dst_bnd_id =
32008  tmp_polyline_pt->final_vertex_connected_bnd_id();
32009 
32010  // Include the destination boundary id to the set of
32011  // boundaries with connections
32012  boundary_id_with_connections.insert(dst_bnd_id);
32013 
32014  } // if (tmp_polyline_pt->is_final_vertex_connected())
32015 
32016  } // for (p < n_polyline)
32017 
32018  } // for (i < n_internal_boundaries)
32019 
32020  // ------------------------------------------------------------------
32021  // Open boundaries (nonclosed internal boundaries)
32022  // ------------------------------------------------------------------
32023 
32024  // Get the number of internal boundaries (open boundaries)
32025  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32026 
32027  // Loop over the internal open boundaries
32028  for (unsigned i = 0; i < n_open_boundaries; i++)
32029  {
32030  // Get a temporary representation for the open curve
32031  TriangleMeshOpenCurve* tmp_open_curve_pt =
32032  this->Internal_open_curve_pt[i];
32033 
32034  // Get the number of curve sections associated to the current
32035  // internal open boundary
32036  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32037 
32038  // Loop over the curve section
32039  for (unsigned p = 0; p < n_curve_section; p++)
32040  {
32041  // Get a temporary representation of the curve section
32042  // (polyline)
32043  TriangleMeshPolyLine* tmp_polyline_pt =
32044  tmp_open_curve_pt->polyline_pt(p);
32045 
32046  // Is the initial vertex connected?
32047  if (tmp_polyline_pt->is_initial_vertex_connected())
32048  {
32049  // Get the boundary id of the current polyline
32050  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32051 
32052  // Include the boundary id to the set of boundaries with
32053  // connections
32054  boundary_id_with_connections.insert(bnd_id);
32055 
32056  // Boundary id to which the curve is connecte
32057  const unsigned dst_bnd_id =
32058  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32059 
32060  // Include the destination boundary id to the set of
32061  // boundaries with connections
32062  boundary_id_with_connections.insert(dst_bnd_id);
32063 
32064  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32065 
32066  // Is the final vertex connected?
32067  if (tmp_polyline_pt->is_final_vertex_connected())
32068  {
32069  // Get the boundary id of the current polyline
32070  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32071 
32072  // Include the boundary id to the set of boundaries with
32073  // connections
32074  boundary_id_with_connections.insert(bnd_id);
32075 
32076  // Boundary id to which the curve is connected
32077  const unsigned dst_bnd_id =
32078  tmp_polyline_pt->final_vertex_connected_bnd_id();
32079 
32080  // Include the destination boundary id to the set of
32081  // boundaries with connections
32082  boundary_id_with_connections.insert(dst_bnd_id);
32083 
32084  } // if (tmp_polyline_pt->is_final_vertex_connected())
32085 
32086  } // for (p < n_curve_section)
32087 
32088  } // for (i < n_open_boundaries)
32089 
32090 #ifdef OOMPH_HAS_MPI
32091  // ------------------------------------------------------------------
32092  // Shared boundaries (only for distributed meshes)
32093  // ------------------------------------------------------------------
32094 
32095  // Check if we need to include any information associated with
32096  // shared boundaries
32097  if (this->is_mesh_distributed())
32098  {
32099  // Get the rank of the current processor
32100  const unsigned my_rank = this->communicator_pt()->my_rank();
32101 
32102  // Get the number of shared curves in the current processor
32103  const unsigned n_shared_curves = this->nshared_boundary_curves(my_rank);
32104 
32105  // Loop over the shared curves
32106  for (unsigned i = 0; i < n_shared_curves; i++)
32107  {
32108  // Get the number of polylines associated to the current shared
32109  // curve
32110  const unsigned n_polyline = this->nshared_boundary_polyline(my_rank, i);
32111 
32112  // Loop over the polylines associated to the current shared
32113  // curve
32114  for (unsigned p = 0; p < n_polyline; p++)
32115  {
32116  // Get a temporary representation of the shared polyline
32117  TriangleMeshPolyLine* tmp_polyline_pt =
32118  this->shared_boundary_polyline_pt(my_rank, i, p);
32119 
32120  // Is the initial vertex connected?
32121  if (tmp_polyline_pt->is_initial_vertex_connected())
32122  {
32123  // Get the boundary id of the current polyline
32124  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32125 
32126  // Include the boundary id to the set of boundaries with
32127  // connections
32128  boundary_id_with_connections.insert(bnd_id);
32129 
32130  // Boundary id to which the curve is connecte
32131  const unsigned dst_bnd_id =
32132  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32133 
32134  // Include the destination boundary id to the set of
32135  // boundaries with connections
32136  boundary_id_with_connections.insert(dst_bnd_id);
32137 
32138  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32139 
32140  // Is the final vertex connected?
32141  if (tmp_polyline_pt->is_final_vertex_connected())
32142  {
32143  // Get the boundary id of the current polyline
32144  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32145 
32146  // Include the boundary id to the set of boundaries with
32147  // connections
32148  boundary_id_with_connections.insert(bnd_id);
32149 
32150  // Boundary id to which the curve is connected
32151  const unsigned dst_bnd_id =
32152  tmp_polyline_pt->final_vertex_connected_bnd_id();
32153 
32154  // Include the destination boundary id to the set of
32155  // boundaries with connections
32156  boundary_id_with_connections.insert(dst_bnd_id);
32157 
32158  } // if (tmp_polyline_pt->is_final_vertex_connected())
32159 
32160  } // for (p < n_polyline)
32161 
32162  } // for (i < n_shared_curves)
32163 
32164  } // if (this->is_mesh_distributed())
32165 
32166 #endif // #ifdef OOMPH_HAS_MPI
32167 
32168  // ---------------------------------------------------------------
32169  // Get the nodes sorted by segments of the boundaries with
32170  // connections
32171 
32172  // Store the sorted nodes by segments of the boundaries with
32173  // connections
32174  std::map<unsigned, Vector<Vector<Node*>>> bnd_sorted_segment_node_pt;
32175 
32176  // Loop over the boundaries with connections
32177  for (std::set<unsigned>::iterator it = boundary_id_with_connections.begin();
32178  it != boundary_id_with_connections.end();
32179  it++)
32180  {
32181  // Get the boundary id
32182  const unsigned bnd_id = (*it);
32183 #ifdef OOMPH_HAS_MPI
32184  // Working with a distributed mesh
32185  if (this->is_mesh_distributed())
32186  {
32187  // Get the initial shared boundary id
32188  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32189  // Is an original or shared boundary
32190  if (bnd_id >= init_shd_bnd_id)
32191  {
32192  // Is a shared boundary
32193 
32194  // Temporary storage for the nodes on the shared boundary
32195  Vector<Vector<Node*>> tmp_shared_nodes_pt;
32196 
32197  // Get the nodes associated to the shared boundary
32198  get_shared_boundary_segment_nodes_helper(bnd_id, tmp_shared_nodes_pt);
32199 
32200  // Store the nodes associated to the shared boundary
32201  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
32202 
32203  } // if (bnd_id >= init_shd_bnd_id)
32204  else
32205  {
32206  // Is an original boundary
32207 
32208  // Temporary storage for the nodes on the original boundary
32209  Vector<Vector<Node*>> tmp_boundary_nodes_pt;
32210 
32211  // Get the nodes associated to the shared boundary
32212  get_boundary_segment_nodes_helper(bnd_id, tmp_boundary_nodes_pt);
32213 
32214  // Store the nodes associated to the shared boundary
32215  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
32216 
32217  } // if (bnd_id >= init_shd_bnd_id)
32218 
32219  } // if (this->is_mesh_distributed())
32220  else
32221 #endif // #ifdef OOMPH_HAS_MPI
32222  {
32223  // Is an original boundary
32224 
32225  // Temporary storage for the nodes on the original boundary
32226  Vector<Vector<Node*>> tmp_boundary_nodes_pt;
32227 
32228  // Get the nodes associated to the shared boundary
32229  get_boundary_segment_nodes_helper(bnd_id, tmp_boundary_nodes_pt);
32230 
32231  // Store the nodes associated to the shared boundary
32232  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
32233 
32234  } // if (this->is_mesh_distributed())
32235 
32236  } // Loop over boundaries with connections
32237 
32238  // -----------------------------------------------------------------
32239  // Loop again over the boundaries (original and shared) and search
32240  // for the repeated nodes in those boundaries with connections
32241 
32242  // ------------------------------------------------------------------
32243  // Outer boundaries
32244  // ------------------------------------------------------------------
32245  // Loop over the outer boundaries
32246  for (unsigned i = 0; i < n_outer_boundaries; i++)
32247  {
32248  // Get a temporary polygon representation
32249  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32250  // Get the number of polylines associated to the current outer
32251  // boundary
32252  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32253  // Loop over the polylines
32254  for (unsigned p = 0; p < n_polyline; p++)
32255  {
32256  // Get a temporary representation of the polyline
32257  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
32258 
32259  // Is the initial vertex connected?
32260  if (tmp_polyline_pt->is_initial_vertex_connected())
32261  {
32262  // Get the boundary id of the current polyline
32263  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32264 
32265  // Boundary id to which the curve is connected
32266  const unsigned dst_bnd_id =
32267  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32268 
32269  // Boundary chunk to which the curve is connected
32270  const unsigned dst_chunk =
32271  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32272 
32273  // Get the nodes representation of the current boundary
32274  Vector<Vector<Node*>> src_bnd_node_pt =
32275  bnd_sorted_segment_node_pt[bnd_id];
32276 
32277  // Get the nodes representation of the boundary to connect
32278  Vector<Vector<Node*>> dst_bnd_node_pt =
32279  bnd_sorted_segment_node_pt[dst_bnd_id];
32280 
32281  // Add the repeated node to the list of non delete-able
32282  // vertices
32283  add_non_delete_vertices_from_boundary_helper(
32284  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32285 
32286  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32287 
32288  // Is the final vertex connected?
32289  if (tmp_polyline_pt->is_final_vertex_connected())
32290  {
32291  // Get the boundary id of the current polyline
32292  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32293 
32294  // Boundary id to which the curve is connected
32295  const unsigned dst_bnd_id =
32296  tmp_polyline_pt->final_vertex_connected_bnd_id();
32297 
32298  // Boundary chunk to which the curve is connected
32299  const unsigned dst_chunk =
32300  tmp_polyline_pt->final_vertex_connected_n_chunk();
32301 
32302  // Get the nodes representation of the current boundary
32303  Vector<Vector<Node*>> src_bnd_node_pt =
32304  bnd_sorted_segment_node_pt[bnd_id];
32305 
32306  // Get the nodes representation of the boundary to connect
32307  Vector<Vector<Node*>> dst_bnd_node_pt =
32308  bnd_sorted_segment_node_pt[dst_bnd_id];
32309 
32310  // Add the repeated node to the list of non delete-able
32311  // vertices
32312  add_non_delete_vertices_from_boundary_helper(
32313  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32314 
32315  } // if (tmp_polyline_pt->is_final_vertex_connected())
32316 
32317  } // for (p < n_polyline)
32318 
32319  } // for (i < n_outer_boundaries)
32320 
32321  // ------------------------------------------------------------------
32322  // Internal boundaries
32323  // ------------------------------------------------------------------
32324  // Loop over the internal boundaries
32325  for (unsigned i = 0; i < n_internal_boundaries; i++)
32326  {
32327  // Get a temporary polygon representation
32328  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32329  // Get the number of polylines associated to the current internal
32330  // boundary
32331  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32332  // Loop over the polylines
32333  for (unsigned p = 0; p < n_polyline; p++)
32334  {
32335  // Get a temporary representation of the polyline
32336  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
32337 
32338  // Is the initial vertex connected?
32339  if (tmp_polyline_pt->is_initial_vertex_connected())
32340  {
32341  // Get the boundary id of the current polyline
32342  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32343 
32344  // Boundary id to which the curve is connected
32345  const unsigned dst_bnd_id =
32346  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32347 
32348  // Boundary chunk to which the curve is connected
32349  const unsigned dst_chunk =
32350  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32351 
32352  // Get the nodes representation of the current boundary
32353  Vector<Vector<Node*>> src_bnd_node_pt =
32354  bnd_sorted_segment_node_pt[bnd_id];
32355 
32356  // Get the nodes representation of the boundary to connect
32357  Vector<Vector<Node*>> dst_bnd_node_pt =
32358  bnd_sorted_segment_node_pt[dst_bnd_id];
32359 
32360  // Add the repeated node to the list of non delete-able
32361  // vertices
32362  add_non_delete_vertices_from_boundary_helper(
32363  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32364 
32365  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32366 
32367  // Is the final vertex connected?
32368  if (tmp_polyline_pt->is_final_vertex_connected())
32369  {
32370  // Get the boundary id of the current polyline
32371  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32372 
32373  // Boundary id to which the curve is connected
32374  const unsigned dst_bnd_id =
32375  tmp_polyline_pt->final_vertex_connected_bnd_id();
32376 
32377  // Boundary chunk to which the curve is connected
32378  const unsigned dst_chunk =
32379  tmp_polyline_pt->final_vertex_connected_n_chunk();
32380 
32381  // Get the nodes representation of the current boundary
32382  Vector<Vector<Node*>> src_bnd_node_pt =
32383  bnd_sorted_segment_node_pt[bnd_id];
32384 
32385  // Get the nodes representation of the boundary to connect
32386  Vector<Vector<Node*>> dst_bnd_node_pt =
32387  bnd_sorted_segment_node_pt[dst_bnd_id];
32388 
32389  // Add the repeated node to the list of non delete-able
32390  // vertices
32391  add_non_delete_vertices_from_boundary_helper(
32392  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32393 
32394  } // if (tmp_polyline_pt->is_final_vertex_connected())
32395 
32396  } // for (p < n_polyline)
32397 
32398  } // for (i < n_internal_boundaries)
32399 
32400  // ------------------------------------------------------------------
32401  // Open boundaries (nonclosed internal boundaries)
32402  // ------------------------------------------------------------------
32403  // Loop over the internal open boundaries
32404  for (unsigned i = 0; i < n_open_boundaries; i++)
32405  {
32406  // Get a temporary representation for the open curve
32407  TriangleMeshOpenCurve* tmp_open_curve_pt =
32408  this->Internal_open_curve_pt[i];
32409 
32410  // Get the number of curve sections associated to the current
32411  // internal open boundary
32412  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32413 
32414  // Loop over the curve section
32415  for (unsigned p = 0; p < n_curve_section; p++)
32416  {
32417  // Get a temporary representation of the curve section
32418  // (polyline)
32419  TriangleMeshPolyLine* tmp_polyline_pt =
32420  tmp_open_curve_pt->polyline_pt(p);
32421 
32422  // Is the initial vertex connected?
32423  if (tmp_polyline_pt->is_initial_vertex_connected())
32424  {
32425  // Get the boundary id of the current polyline
32426  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32427 
32428  // Boundary id to which the curve is connected
32429  const unsigned dst_bnd_id =
32430  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32431 
32432  // Boundary chunk to which the curve is connected
32433  const unsigned dst_chunk =
32434  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32435 
32436  // Get the nodes representation of the current boundary
32437  Vector<Vector<Node*>> src_bnd_node_pt =
32438  bnd_sorted_segment_node_pt[bnd_id];
32439 
32440  // Get the nodes representation of the boundary to connect
32441  Vector<Vector<Node*>> dst_bnd_node_pt =
32442  bnd_sorted_segment_node_pt[dst_bnd_id];
32443 
32444  // Add the repeated node to the list of non delete-able
32445  // vertices
32446  add_non_delete_vertices_from_boundary_helper(
32447  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32448 
32449  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32450 
32451  // Is the final vertex connected?
32452  if (tmp_polyline_pt->is_final_vertex_connected())
32453  {
32454  // Get the boundary id of the current polyline
32455  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32456 
32457  // Boundary id to which the curve is connected
32458  const unsigned dst_bnd_id =
32459  tmp_polyline_pt->final_vertex_connected_bnd_id();
32460 
32461  // Boundary chunk to which the curve is connected
32462  const unsigned dst_chunk =
32463  tmp_polyline_pt->final_vertex_connected_n_chunk();
32464 
32465  // Get the nodes representation of the current boundary
32466  Vector<Vector<Node*>> src_bnd_node_pt =
32467  bnd_sorted_segment_node_pt[bnd_id];
32468 
32469  // Get the nodes representation of the boundary to connect
32470  Vector<Vector<Node*>> dst_bnd_node_pt =
32471  bnd_sorted_segment_node_pt[dst_bnd_id];
32472 
32473  // Add the repeated node to the list of non delete-able
32474  // vertices
32475  add_non_delete_vertices_from_boundary_helper(
32476  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32477 
32478  } // if (tmp_polyline_pt->is_final_vertex_connected())
32479 
32480  } // for (p < n_curve_section)
32481 
32482  } // for (i < n_open_boundaries)
32483 
32484 #ifdef OOMPH_HAS_MPI
32485  // ------------------------------------------------------------------
32486  // Shared boundaries (only for distributed meshes)
32487  // ------------------------------------------------------------------
32488 
32489  // Check if we need to include any information associated with
32490  // shared boundaries
32491  if (this->is_mesh_distributed())
32492  {
32493  // Get the rank of the current processor
32494  const unsigned my_rank = this->communicator_pt()->my_rank();
32495 
32496  // Get the number of shared curves in the current processor
32497  const unsigned n_shared_curves = this->nshared_boundary_curves(my_rank);
32498 
32499  // Loop over the shared curves
32500  for (unsigned i = 0; i < n_shared_curves; i++)
32501  {
32502  // Get the number of polylines associated to the current shared
32503  // curve
32504  const unsigned n_polyline = this->nshared_boundary_polyline(my_rank, i);
32505 
32506  // Loop over the polylines associated to the current shared
32507  // curve
32508  for (unsigned p = 0; p < n_polyline; p++)
32509  {
32510  // Get a temporary representation of the shared polyline
32511  TriangleMeshPolyLine* tmp_polyline_pt =
32512  this->shared_boundary_polyline_pt(my_rank, i, p);
32513 
32514  // Is the initial vertex connected?
32515  if (tmp_polyline_pt->is_initial_vertex_connected())
32516  {
32517  // Get the boundary id of the current polyline
32518  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32519 
32520  // Boundary id to which the curve is connected
32521  const unsigned dst_bnd_id =
32522  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32523 
32524  // Boundary chunk to which the curve is connected
32525  const unsigned dst_chunk =
32526  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32527 
32528  // Get the nodes representation of the current boundary
32529  Vector<Vector<Node*>> src_bnd_node_pt =
32530  bnd_sorted_segment_node_pt[bnd_id];
32531 
32532  // Get the nodes representation of the boundary to connect
32533  Vector<Vector<Node*>> dst_bnd_node_pt =
32534  bnd_sorted_segment_node_pt[dst_bnd_id];
32535 
32536  // Add the repeated node to the list of non delete-able
32537  // vertices
32538  add_non_delete_vertices_from_boundary_helper(
32539  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32540 
32541  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32542 
32543  // Is the final vertex connected?
32544  if (tmp_polyline_pt->is_final_vertex_connected())
32545  {
32546  // Get the boundary id of the current polyline
32547  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32548 
32549  // Boundary id to which the curve is connected
32550  const unsigned dst_bnd_id =
32551  tmp_polyline_pt->final_vertex_connected_bnd_id();
32552 
32553  // Boundary chunk to which the curve is connected
32554  const unsigned dst_chunk =
32555  tmp_polyline_pt->final_vertex_connected_n_chunk();
32556 
32557  // Get the nodes representation of the current boundary
32558  Vector<Vector<Node*>> src_bnd_node_pt =
32559  bnd_sorted_segment_node_pt[bnd_id];
32560 
32561  // Get the nodes representation of the boundary to connect
32562  Vector<Vector<Node*>> dst_bnd_node_pt =
32563  bnd_sorted_segment_node_pt[dst_bnd_id];
32564 
32565  // Add the repeated node to the list of non delete-able
32566  // vertices
32567  add_non_delete_vertices_from_boundary_helper(
32568  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32569 
32570  } // if (tmp_polyline_pt->is_final_vertex_connected())
32571 
32572  } // for (p < n_polyline)
32573 
32574  } // for (i < n_shared_curves)
32575 
32576  } // if (this->is_mesh_distributed())
32577 
32578 #endif // #ifdef OOMPH_HAS_MPI
32579  }
32580 
32581  //=========================================================================
32582  /// \short Adds the vertices from the sources boundary that are
32583  /// repeated in the destination boundary to the list of non
32584  /// delete-able vertices in the destination boundary
32585  //=========================================================================
32586  template<class ELEMENT>
32589  Vector<Vector<Node*>> src_bound_segment_node_pt,
32590  Vector<Vector<Node*>> dst_bound_segment_node_pt,
32591  const unsigned& dst_bnd_id,
32592  const unsigned& dst_bnd_chunk)
32593  {
32594  // Get the number of segments in the source boundary
32595  const unsigned n_seg = src_bound_segment_node_pt.size();
32596  // Loop over the segments in the source boundary
32597  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32598  {
32599  // Get the number of nodes in the current segment
32600  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32601  // Get the left and right node of the current segment
32602  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32603  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode - 1];
32604 
32605  // Get the number of segments in the destination boundary
32606  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32607  // Loop over the segments in the destination boundary
32608  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32609  {
32610  // Get the number of nodes on the current destination segment
32611  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32612  // Loop over the nodes until the node has been found or we have
32613  // visited all the nodes
32614  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32615  {
32616  // Get a pointer to the jnode in the destination segment
32617  // boundary
32618  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32619  // Is the node the same as the left or right node if
32620  // the source segment boundary
32621  if (tmp_node_pt == left_node_pt)
32622  {
32623  // We have foud the node to connect, get the vertex of the node
32624  Vector<double> vertex(2);
32625  vertex[0] = tmp_node_pt->x(0);
32626  vertex[1] = tmp_node_pt->x(1);
32627 
32628  // Establish the vertex coordinate as untouchable in the
32629  // destination boundary during the adaptation process. It
32630  // means that unrefinement can not take off the vertices
32631  // that receive connections in the destination boundary
32632  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32633  // Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32634  // insert(vertex);
32635 
32636  // return
32637  return;
32638 
32639  } // if (tmp_node_pt == left_node_pt)
32640  else if (tmp_node_pt == right_node_pt)
32641  {
32642  // We have foud the node to connect, get the vertex of the node
32643  Vector<double> vertex(2);
32644  vertex[0] = tmp_node_pt->x(0);
32645  vertex[1] = tmp_node_pt->x(1);
32646 
32647  // Establish the vertex coordinate as untouchable in the
32648  // destination boundary during the adaptation process. It
32649  // means that unrefinement can not take off the vertices
32650  // that receive connections in the destination boundary
32651  // Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32652  // insert(vertex);
32653  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32654 
32655  // return
32656  return;
32657 
32658  } // else if (tmp_node_pt == right_node_pt)
32659 
32660  } // for (jnode < n_dst_node)
32661 
32662  } // for (jseg < n_dst_seg)
32663 
32664  } // for (iseg < n_seg)
32665  }
32666 
32667 #ifdef OOMPH_HAS_MPI
32668  //=========================================================================
32669  /// \short Synchronise the vertices that are marked for non deletion
32670  // on the shared boundaries. Unrefinement of shared boundaries is
32671  // performed only if the candidate node is not marked for non deletion
32672  //=========================================================================
32673  template<class ELEMENT>
32674  const void RefineableTriangleMesh<
32675  ELEMENT>::synchronize_shared_boundary_connections()
32676  {
32677  // Get the number of processors
32678  const unsigned nproc = this->communicator_pt()->nproc();
32679  // Get my rank
32680  const unsigned my_rank = this->communicator_pt()->my_rank();
32681 
32682  // loop over the processors
32683  for (unsigned jproc = 0; jproc < nproc; jproc++)
32684  {
32685  // The number of boundaries shared with the current processor
32686  // (if jproc==my_rank then there are no shared boundaries
32687  // between them)
32688  const unsigned n_shd_bnd_jproc = this->nshared_boundaries(my_rank, jproc);
32689 
32690  // Are there shared boundaries with the jproc processor?
32691  // There are no info. with myself
32692  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32693  {
32694  // Storage for the boundaries ids with vertices for non
32695  // deletion
32696  Vector<unsigned> shd_bnd_id_for_non_deletion;
32697 
32698  // Storage for chunk numbers of boundaries with vertices
32699  // for non deletion
32700  Vector<unsigned> chunk_for_non_deletion;
32701 
32702  // The number of vertices for nondeletion in the shared
32703  // boundaries
32704  Vector<unsigned> number_vertices_non_deletion;
32705 
32706  // Vertices marked for nondeletion in shared boundaries
32707  Vector<Vector<Vector<double>>> vertices_for_non_deletion;
32708 
32709  // Get the boundary ids of the shared boundaries with jproc
32710  // processor
32711  Vector<unsigned> shd_bnd_ids =
32712  this->shared_boundaries_ids(my_rank, jproc);
32713 
32714  // Get the number of shared boundaries with jproc
32715  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32716  // loop over the shared boundaries with jproc
32717  for (unsigned ishd_bnd = 0; ishd_bnd < n_shd_bnd_jproc; ishd_bnd++)
32718  {
32719  // Get the shared boudary id
32720  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32721  // Get the associated polyline
32722  TriangleMeshPolyLine* shd_polyline_pt =
32723  this->boundary_polyline_pt(shd_bnd_id);
32724  // Get the chunk number
32725  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32726 
32727  // Store the vertices not allowed for deletion
32728  std::set<Vector<double>> no_delete_vertex;
32729 
32730  // Does the boundary has vertives for nondeleteion?
32731  const bool boundary_receive_connections =
32732  this->boundary_connections(shd_bnd_id, chunk, no_delete_vertex);
32733 
32734  // Get the number of vertices for nondeletion
32735  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32736 
32737  // Are there vertices for nondeletion?
32738  if (boundary_receive_connections && n_non_delete_vertex > 0)
32739  {
32740  // Add the shared boundary id
32741  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32742  // Add the chunk number
32743  chunk_for_non_deletion.push_back(chunk);
32744  // Add the number of vertices for non deletion
32745  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32746 
32747  // The list of vertices to add
32748  Vector<Vector<double>> tmp_vertices;
32749 
32750  // Add the vertices for non deletion
32751  for (std::set<Vector<double>>::iterator it =
32752  no_delete_vertex.begin();
32753  it != no_delete_vertex.end();
32754  it++)
32755  {
32756  // Get the vertex coordinate
32757  Vector<double> vertex = (*it);
32758  tmp_vertices.push_back(vertex);
32759  }
32760 
32761  // Add the vertices coordinates to a vector storage
32762  vertices_for_non_deletion.push_back(tmp_vertices);
32763 
32764  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32765 
32766  } // for (ishd_bnd<n_shd_bnd_jproc)
32767 
32768  // ----------------------------------------------------------
32769  // ----------------------------------------------------------
32770  // ----------------------------------------------------------
32771  // Now send the info. to the other processor (jproc)
32772  // ----------------------------------------------------------
32773  // ----------------------------------------------------------
32774  // ----------------------------------------------------------
32775  // Get the communicator of the mesh
32776  OomphCommunicator* comm_pt = this->communicator_pt();
32777 
32778  // Set MPI info
32779  MPI_Status status;
32780  MPI_Request request;
32781 
32782  // -----------------------------------------------------------
32783  // Prepare the data
32784  // Get the number of shared boundaires with vertices marked
32785  // for non deletion
32786  const unsigned n_shd_bnd_with_non_delete_vertices =
32787  shd_bnd_id_for_non_deletion.size();
32788 
32789  // Size of the package
32790  const unsigned size_package = 3;
32791  // Ndata to send
32792  const unsigned n_unsigned_data_to_send =
32793  n_shd_bnd_with_non_delete_vertices * size_package;
32794  // The flat package to send the info.
32795  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32796  Vector<double> flat_package_double_send;
32797 
32798  Vector<unsigned> flat_package_unsigned_recv;
32799  Vector<double> flat_package_double_recv;
32800 
32801  // Prepare the data to be sent
32802  unsigned j = 0;
32803  for (unsigned i = 0; i < n_shd_bnd_with_non_delete_vertices; i++)
32804  {
32805  // The shared boundary id
32806  flat_package_unsigned_send[j++] = shd_bnd_id_for_non_deletion[i];
32807  // The chunk number
32808  flat_package_unsigned_send[j++] = chunk_for_non_deletion[i];
32809  // The number of vertices for nondeletion
32810  flat_package_unsigned_send[j++] = number_vertices_non_deletion[i];
32811  // Also package the vertices
32812  const unsigned n_vertices_non_deletion =
32813  number_vertices_non_deletion[i];
32814  // Loop over the vertices and store them in the flat
32815  // package to be sent
32816  for (unsigned h = 0; h < n_vertices_non_deletion; h++)
32817  {
32818  flat_package_double_send.push_back(
32819  vertices_for_non_deletion[i][h][0]);
32820  flat_package_double_send.push_back(
32821  vertices_for_non_deletion[i][h][1]);
32822  } // for (h<n_vertices_non_deletion)
32823 
32824  } // for (i<n_shd_bnd_with_non_delete_vertices)
32825 
32826  // ----------------------------------------------------------
32827  int send_proc = jproc;
32828  int recv_proc = jproc;
32829  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32830  unsigned send_count_double_values = flat_package_double_send.size();
32831  //-----------------------------------------------------------
32832  // Do the transfering of info.
32833  //-----------------------------------------------------------
32834  // Start with UNSIGNED info.
32835  MPI_Isend(&send_count_unsigned_values,
32836  1,
32837  MPI_UNSIGNED,
32838  send_proc,
32839  1,
32840  comm_pt->mpi_comm(),
32841  &request);
32842 
32843  unsigned receive_count_unsigned_values = 0;
32844  MPI_Recv(&receive_count_unsigned_values,
32845  1,
32846  MPI_UNSIGNED,
32847  recv_proc,
32848  1,
32849  comm_pt->mpi_comm(),
32850  &status);
32851 
32852  MPI_Wait(&request, MPI_STATUS_IGNORE);
32853 
32854  // Send the actual data
32855  if (send_count_unsigned_values != 0)
32856  {
32857  MPI_Isend(&flat_package_unsigned_send[0],
32858  send_count_unsigned_values,
32859  MPI_UNSIGNED,
32860  send_proc,
32861  2,
32862  comm_pt->mpi_comm(),
32863  &request);
32864  }
32865 
32866  // Receive the actual data
32867  if (receive_count_unsigned_values != 0)
32868  {
32869  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32870  MPI_Recv(&flat_package_unsigned_recv[0],
32871  receive_count_unsigned_values,
32872  MPI_UNSIGNED,
32873  recv_proc,
32874  2,
32875  comm_pt->mpi_comm(),
32876  &status);
32877  }
32878 
32879  // Wait for sending the data and the other processor
32880  // receives
32881  if (send_count_unsigned_values != 0)
32882  {
32883  MPI_Wait(&request, MPI_STATUS_IGNORE);
32884  }
32885 
32886  //-----------------------------------------------------------
32887  // Then continue with DOUBLE info.
32888  MPI_Isend(&send_count_double_values,
32889  1,
32890  MPI_UNSIGNED,
32891  send_proc,
32892  1,
32893  comm_pt->mpi_comm(),
32894  &request);
32895 
32896  unsigned receive_count_double_values = 0;
32897  MPI_Recv(&receive_count_double_values,
32898  1,
32899  MPI_UNSIGNED,
32900  recv_proc,
32901  1,
32902  comm_pt->mpi_comm(),
32903  &status);
32904 
32905  MPI_Wait(&request, MPI_STATUS_IGNORE);
32906 
32907  // Send the actual data
32908  if (send_count_double_values != 0)
32909  {
32910  MPI_Isend(&flat_package_double_send[0],
32911  send_count_double_values,
32912  MPI_DOUBLE,
32913  send_proc,
32914  2,
32915  comm_pt->mpi_comm(),
32916  &request);
32917  }
32918 
32919  // Receive the actual data
32920  if (receive_count_double_values != 0)
32921  {
32922  flat_package_double_recv.resize(receive_count_double_values);
32923  MPI_Recv(&flat_package_double_recv[0],
32924  receive_count_double_values,
32925  MPI_DOUBLE,
32926  recv_proc,
32927  2,
32928  comm_pt->mpi_comm(),
32929  &status);
32930  }
32931 
32932  // Wait for sending the data and the other processor
32933  // receives
32934  if (send_count_double_values != 0)
32935  {
32936  MPI_Wait(&request, MPI_STATUS_IGNORE);
32937  }
32938 
32939  // ------------------------------------------------------------
32940  // ------------------------------------------------------------
32941  // ------------------------------------------------------------
32942  // Now unpackage the data
32943  // ------------------------------------------------------------
32944  // ------------------------------------------------------------
32945  // ------------------------------------------------------------
32946 
32947  // Storage for the boundaries ids with vertices for non
32948  // deletion
32949  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32950 
32951  // Storage for chunk numbers of boundaries with vertices
32952  // for non deletion
32953  Vector<unsigned> recv_chunk_for_non_deletion;
32954 
32955  // The number of vertices for nondeletion in the shared
32956  // boundaries
32957  Vector<unsigned> recv_number_vertices_non_deletion;
32958 
32959  // Vertices marked for nondeletion in shared boundaries
32960  Vector<Vector<Vector<double>>> recv_vertices_for_non_deletion;
32961 
32962  // Counter
32963  j = 0;
32964  for (unsigned i = 0; i < receive_count_unsigned_values; i += 3)
32965  {
32966  // Get the shared boundary id
32967  const unsigned recv_shd_bnd_id = flat_package_unsigned_recv[i];
32968  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32969  // Get the chunk number
32970  const unsigned recv_chunk = flat_package_unsigned_recv[i + 1];
32971  recv_chunk_for_non_deletion.push_back(recv_chunk);
32972  // Get the number of vertices for non deletion
32973  const unsigned recv_num_vertices = flat_package_unsigned_recv[i + 2];
32974  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32975 
32976  // Create a temporal storage
32977  Vector<Vector<double>> temp_recv_vertices;
32978  // Now get the vertices
32979  for (unsigned h = 0; h < recv_num_vertices; h++)
32980  {
32981  Vector<double> tmp_vertex(2);
32982  tmp_vertex[0] = flat_package_double_recv[j++];
32983  tmp_vertex[1] = flat_package_double_recv[j++];
32984  // Add the vertex to the vector of vertices
32985  temp_recv_vertices.push_back(tmp_vertex);
32986  } // for (h<recv_num_vertices)
32987 
32988  // Add the vertices to the vector of vertices
32989  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32990 
32991  } // for(i<receive_count_unsigned_values)
32992 
32993  // ---------------------------------------------------------
32994  // ---------------------------------------------------------
32995  // ---------------------------------------------------------
32996  // Now add the vertices to the data structures to mark them
32997  // as non delete-able
32998  // ---------------------------------------------------------
32999  // ---------------------------------------------------------
33000  // ---------------------------------------------------------
33001 
33002  // Get the number of shd boundaries that have vertices
33003  // marked for non deletion
33004  const unsigned n_recv_shd_bnd_id_for_non_deletion =
33005  recv_shd_bnd_id_for_non_deletion.size();
33006  // loop over the shared boundaries and add the data for non
33007  // deletion
33008  for (unsigned i = 0; i < n_recv_shd_bnd_id_for_non_deletion; i++)
33009  {
33010  // Get the shared boundary id.
33011  const unsigned shd_bnd_id = recv_shd_bnd_id_for_non_deletion[i];
33012  // Get the chunk number
33013  unsigned chunk = recv_chunk_for_non_deletion[i];
33014  // Increase and decrease the chunk number to avoid the
33015  // warning when compiling without PARANOID
33016  chunk++;
33017  chunk--;
33018 
33019  // Get the number of vertices marked for non deletion
33020  const unsigned n_vertices = recv_number_vertices_non_deletion[i];
33021  // Add all the vertices
33022  for (unsigned h = 0; h < n_vertices; h++)
33023  {
33024  // Get the vertex
33025  Vector<double> vertex(2);
33026  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
33027  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
33028  // Add the vertex to the data structure for non
33029  // deletion
33030  // Boundary_chunk_connections_pt[shd_bnd_id][chunk].
33031  // insert(vertex);
33032  Boundary_connections_pt[shd_bnd_id].insert(vertex);
33033 
33034  } // for (h<n_vertices)
33035 
33036  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
33037 
33038  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
33039 
33040  } // for (jproc < nproc)
33041  }
33042 #endif // #ifdef OOMPH_HAS_MPI
33043 
33044  //=========================================================================
33045  /// \short After unrefinement and refinement has taken place compute
33046  /// the new vertices numbers of the temporary representation of the
33047  // boundaries to connect.
33048  //=========================================================================
33049  template<class ELEMENT>
33051  Vector<TriangleMeshPolygon*>& tmp_outer_polygons_pt,
33052  Vector<TriangleMeshOpenCurve*>& tmp_open_curves_pt)
33053  {
33054  // Dummy storages
33055  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
33056  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
33057 
33058  // Clear the storage
33059  dummy_resume_initial_connection_polyline_pt.clear();
33060  dummy_resume_final_connection_polyline_pt.clear();
33061 
33062  // Get the initial shared boundary id (to check whether the
33063  // polylines represent original or shared boundaries)
33064  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33065 
33066  // ------------------------------------------------------------------
33067  // This seems unnecesary since the outer polygons does not create
33068  // connections with other boundaries (the original ones)
33069  // ------------------------------------------------------------------
33070  // Unnecessary?
33071  // ------------------------------------------------------------------
33072 
33073  // Loop over the temporary outer polygons create the connection
33074  // information of those boundaries marked to be connected at their
33075  // ends
33076 
33077  // ------------------------------------------------------------------
33078  // Temporary outer polygons
33079  // ------------------------------------------------------------------
33080 
33081  // Get the number of outer boundaries (closed boundaries)
33082  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
33083 
33084  // Loop over the outer boundaries
33085  for (unsigned i = 0; i < n_outer_boundaries; i++)
33086  {
33087  // Get a temporary polygon representation
33088  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
33089  // Get the number of polylines associated to the current outer
33090  // boundary
33091  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33092  // Loop over the polylines
33093  for (unsigned p = 0; p < n_polyline; p++)
33094  {
33095  // Get a temporary representation of the polyline
33096  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33097 
33098  // Get the boundary id
33099  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
33100 
33101  // Is the boundary to connect a shared boundary
33102  if (bnd_id < init_shd_bnd_id)
33103  {
33104  // Restore the connections of the current polyline
33105  restore_polyline_connections_helper(
33106  tmp_polyline_pt,
33107  dummy_resume_initial_connection_polyline_pt,
33108  dummy_resume_final_connection_polyline_pt);
33109 
33110  } // if (bnd_id < init_shd_bnd_id)
33111 
33112  } // for (p < n_polyline)
33113 
33114  } // for (i < n_outer_boundaries)
33115 
33116  // ------------------------------------------------------------------
33117  // Unnecessary?
33118  // ------------------------------------------------------------------
33119 
33120  // ------------------------------------------------------------------
33121  // Temporary open boundaries (nonclosed internal boundaries)
33122  // ------------------------------------------------------------------
33123 
33124  // Get the number of internal boundaries (open boundaries)
33125  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
33126 
33127  // Loop over the internal open boundaries
33128  for (unsigned i = 0; i < n_open_boundaries; i++)
33129  {
33130  // Get a temporary representation for the open curve
33131  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
33132 
33133  // Get the number of curve sections associated to the current
33134  // internal open boundary
33135  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
33136 
33137  // Loop over the curve section
33138  for (unsigned p = 0; p < n_curve_section; p++)
33139  {
33140  // Get a temporary representation of the curve section
33141  // (polyline)
33142  TriangleMeshPolyLine* tmp_polyline_pt =
33143  tmp_open_curve_pt->polyline_pt(p);
33144 
33145  // Get the boundary id
33146  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
33147 
33148  // Is the boundary to connect a shared boundary
33149  if (bnd_id < init_shd_bnd_id)
33150  {
33151  // Restore the connections of the current polyline
33152  restore_polyline_connections_helper(
33153  tmp_polyline_pt,
33154  dummy_resume_initial_connection_polyline_pt,
33155  dummy_resume_final_connection_polyline_pt);
33156 
33157  } // if (bnd_id < init_shd_bnd_id)
33158 
33159  } // for (p < n_curve_section)
33160 
33161  } // for (i < n_open_boundaries)
33162  }
33163 
33164  //=========================================================================
33165  /// \short After unrefinement and refinement has taken place compute
33166  /// the new vertices numbers of the boundaries to connect (in a
33167  /// distributed scheme it may be possible that the destination
33168  /// boundary does no longer exist, therefore the connection is
33169  /// suspended. It is not permanently deleted because if load balance
33170  /// takes place it may be possible that the boundary to connect be
33171  /// part of the new domain representation, so the connection would
33172  /// exist)
33173  //=========================================================================
33174  template<class ELEMENT>
33176  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
33177  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
33178  {
33179  // Clear the storage
33180  resume_initial_connection_polyline_pt.clear();
33181  resume_final_connection_polyline_pt.clear();
33182 
33183  // Loop over the boundaries in the domain (outer, internal -- closed
33184  // and open) and restore the connection information of those
33185  // boundaries marked to be connected at their ends
33186 
33187  // ------------------------------------------------------------------
33188  // Outer boundaries
33189  // ------------------------------------------------------------------
33190 
33191  // Get the number of outer boundaries (closed boundaries)
33192  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
33193 
33194  // Loop over the outer boundaries
33195  for (unsigned i = 0; i < n_outer_boundaries; i++)
33196  {
33197  // Get a temporary polygon representation
33198  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
33199  // Get the number of polylines associated to the current outer
33200  // boundary
33201  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33202  // Loop over the polylines
33203  for (unsigned p = 0; p < n_polyline; p++)
33204  {
33205  // Get a temporary representation of the polyline
33206  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33207 
33208  // Restore the connections of the current polyline
33209  restore_polyline_connections_helper(
33210  tmp_polyline_pt,
33211  resume_initial_connection_polyline_pt,
33212  resume_final_connection_polyline_pt);
33213 
33214  } // for (p < n_polyline)
33215 
33216  } // for (i < n_outer_boundaries)
33217 
33218  // ------------------------------------------------------------------
33219  // Internal boundaries
33220  // ------------------------------------------------------------------
33221 
33222  // Get the number of internal boundaries (closed boundaries)
33223  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
33224 
33225  // Loop over the internal boundaries
33226  for (unsigned i = 0; i < n_internal_boundaries; i++)
33227  {
33228  // Get a temporary polygon representation
33229  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
33230  // Get the number of polylines associated to the current internal
33231  // boundary
33232  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33233  // Loop over the polylines
33234  for (unsigned p = 0; p < n_polyline; p++)
33235  {
33236  // Get a temporary representation of the polyline
33237  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33238 
33239  // Restore the connections of the current polyline
33240  restore_polyline_connections_helper(
33241  tmp_polyline_pt,
33242  resume_initial_connection_polyline_pt,
33243  resume_final_connection_polyline_pt);
33244 
33245  } // for (p < n_polyline)
33246 
33247  } // for (i < n_internal_boundaries)
33248 
33249  // ------------------------------------------------------------------
33250  // Open boundaries (nonclosed internal boundaries)
33251  // ------------------------------------------------------------------
33252 
33253  // Get the number of internal boundaries (open boundaries)
33254  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
33255 
33256  // Loop over the internal open boundaries
33257  for (unsigned i = 0; i < n_open_boundaries; i++)
33258  {
33259  // Get a temporary representation for the open curve
33260  TriangleMeshOpenCurve* tmp_open_curve_pt =
33261  this->Internal_open_curve_pt[i];
33262 
33263  // Get the number of curve sections associated to the current
33264  // internal open boundary
33265  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
33266 
33267  // Loop over the curve section
33268  for (unsigned p = 0; p < n_curve_section; p++)
33269  {
33270  // Get a temporary representation of the curve section
33271  // (polyline)
33272  TriangleMeshPolyLine* tmp_polyline_pt =
33273  tmp_open_curve_pt->polyline_pt(p);
33274 
33275  // Restore the connections of the current polyline
33276  restore_polyline_connections_helper(
33277  tmp_polyline_pt,
33278  resume_initial_connection_polyline_pt,
33279  resume_final_connection_polyline_pt);
33280 
33281  } // for (p < n_curve_section)
33282 
33283  } // for (i < n_open_boundaries)
33284  }
33285 
33286  //=========================================================================
33287  /// \short Restore the connections of the specific polyline
33288  /// The vertices numbering on the destination boundaries may have
33289  /// change because of (un)refinement in the destination boundaries.
33290  /// Also deals with connection that do not longer exist because the
33291  /// destination boundary does no longer exist because of the distribution
33292  /// process
33293  //=========================================================================
33294  template<class ELEMENT>
33296  TriangleMeshPolyLine* polyline_pt,
33297  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
33298  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
33299  {
33300  // If the polyline is connected at any of its ends compute the new
33301  // vertex number on the destination boundary
33302 
33303  // ------------------------------------------------------------------
33304  // Is the initial vertex connected?
33305  if (polyline_pt->is_initial_vertex_connected())
33306  {
33307  // The pointer to the boundary to connect
33308  TriangleMeshPolyLine* poly_to_connect_pt = 0;
33309 
33310  // Get the boundary id of the destination/connected boundary
33311  const unsigned dst_bnd_id_initial =
33312  polyline_pt->initial_vertex_connected_bnd_id();
33313 
33314  // Get the initial vertex on the current boundary
33315  Vector<double> src_vertex_coordinates_initial =
33316  polyline_pt->vertex_coordinate(0);
33317 
33318 #ifdef PARANOID
33319  // Is the mesh distributed?
33320 #ifdef OOMPH_HAS_MPI
33321  if (this->is_mesh_distributed())
33322  {
33323  // Get the initial shared boundary id
33324  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33325  // Is the boundary to connect a shared boundary
33326  if (dst_bnd_id_initial >= init_shd_bnd_id)
33327  {
33328  // Get the current polyline original boundary id
33329  const unsigned bnd_id = polyline_pt->boundary_id();
33330  std::ostringstream error_message;
33331  error_message
33332  << "INITIAL VERTEX CONNECTION\n"
33333  << "The current original boundary is trying to connect to a\n"
33334  << "shared boundary, this is not allowed. In this case the\n"
33335  << "shared boundary should be the one that connects with the\n"
33336  << "original boundary\n"
33337  << "The current original boundary (" << bnd_id << ") is marked\n"
33338  << "to have a connection at the\nINITIAL vertex ("
33339  << src_vertex_coordinates_initial[0] << ","
33340  << src_vertex_coordinates_initial[1] << ")\n"
33341  << "with the shared boundary (" << dst_bnd_id_initial << ")\n"
33342  << "This is the list of vertices on the shared destination "
33343  "boundary\n";
33344  // Get the pointer to the associated polyline by using the
33345  // boundary id
33346  TriangleMeshPolyLine* dst_polyline =
33347  this->boundary_polyline_pt(dst_bnd_id_initial);
33348  // The number of vertices on the destination boundary
33349  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33350  // Loop over the vertices print them
33351  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33352  {
33353  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33354  error_message << "Vertex#(i): (" << current_vertex[0] << ", "
33355  << current_vertex[1] << ")\n";
33356  }
33357  throw OomphLibError(
33358  error_message.str(),
33359  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33360  OOMPH_EXCEPTION_LOCATION);
33361  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33362 
33363  } // if (this->is_mesh_distributed())
33364 #endif // #ifdef OOMPH_HAS_MPI
33365 
33366 #endif // #ifdef PARANOID
33367 
33368  // Flag to indicate if the vertex was found on the destination
33369  // boundary
33370  bool found_vertex_on_dst_boundary_initial = false;
33371 
33372  // Flag that stores the chunk number to connect (only used in
33373  // distributed meshes)
33374  unsigned sub_poly_to_connect = 0;
33375 
33376  // Store the vertex number on the destination boundary
33377  unsigned n_vertex_connection_initial = 0;
33378 
33379  // Flags only used in a distributed mesh
33380  // ----------------------------------------
33381  // Flag to indicate we are trying to connect to an split boundary
33382  bool connecting_to_an_split_boundary = false;
33383 
33384  // Flag to indicate we are trying to connecto to an internal
33385  // boundary that is overlaped by a shared boundary)
33386  bool connecting_to_an_overlaped_boundary = false;
33387 
33388 #ifdef OOMPH_HAS_MPI
33389  if (this->is_mesh_distributed())
33390  {
33391  // We can only connect to an original boundary, check if the
33392  // boundary was splitted during the distribution process to
33393  // consider all the chunks (sub-polylines) of the boundary
33394  if (this->boundary_was_splitted(dst_bnd_id_initial))
33395  {
33396  connecting_to_an_split_boundary = true;
33397  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33398 
33399  // Check if the destination boundary, or any of its chunks is
33400  // marked to be overlapped by a shared boundary, if that is the
33401  // case we can only connect to the chunks that are not
33402  // overlapped by shared boundaries (the shared boundaries are in
33403  // charge of generating the connections with original boundaries
33404  // and with themselves)
33405  if (connecting_to_an_split_boundary)
33406  {
33407  // Get the number of chucks that represent the destination
33408  // boundary
33409  const unsigned n_sub_poly =
33410  this->nboundary_subpolylines(dst_bnd_id_initial);
33411  // Now loop over the chunks of the destination boundary and if
33412  // any of them is marked to be overlaped by a shared boundary
33413  // then set the flag and break the loop
33414  for (unsigned ii = 0; ii < n_sub_poly; ii++)
33415  {
33416  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_initial,
33417  ii))
33418  {
33419  // Mark the boundary as being overlaped by a shared
33420  // boundary
33421  connecting_to_an_overlaped_boundary = true;
33422  // Break, no need to look for more overlapings
33423  break;
33424  } // if (boundary_marked_as_shared_boundary(...))
33425  } // for (ii < n_sub_poly)
33426  } // if (connecting_to_an_split_boundary)
33427  else
33428  {
33429  // If not connecting to an split boundary then check if the
33430  // whole destination boundary is overlaped by an internal
33431  // boundary
33432  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33433  {
33434  // Mark the boundary as being overlaped by a shared boundary
33435  connecting_to_an_overlaped_boundary = true;
33436  } // if (boundary_marked_as_shared_boundary(...))
33437  } // else if (connecting_to_an_split_boundary)
33438 
33439  } // if (this->is_mesh_distributed())
33440 
33441 #endif // #ifdef OOMPH_HAS_MPI
33442 
33443  // If we are connecting neither to an split boundary nor an
33444  // overlaped boundary then get the pointer to the original
33445  // boundary
33446  if (!(connecting_to_an_split_boundary ||
33447  connecting_to_an_overlaped_boundary))
33448  {
33449  // Get the polyline pointer representing the destination
33450  // boundary
33451  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33452  } // else if (NOT split, NOT overlaped)
33453 
33454  // Now look for the vertex number on the destination boundary(ies)
33455  // -- in case that the boundary was split ---
33456 
33457  // Do not check for same orientation, that was previously worked
33458  // by interchanging the connections boundaries (if necessary)
33459 
33460  // If the boundary was not split then ...
33461  if (!connecting_to_an_split_boundary)
33462  {
33463  // ... check if the boundary is marked to be overlaped by
33464  // a shared boundary
33465  if (!connecting_to_an_overlaped_boundary)
33466  {
33467  // If that is not the case then we can safely look for the
33468  // vertex number on the destination boundary
33469  found_vertex_on_dst_boundary_initial =
33470  this->get_connected_vertex_number_on_destination_polyline(
33471  poly_to_connect_pt,
33472  src_vertex_coordinates_initial,
33473  n_vertex_connection_initial);
33474 
33475  } // if (!connecting_to_an_overlaped_boundary)
33476  else
33477  {
33478  // If the whole boundary is marked to be overlaped by a shared
33479  // boundary then do nothing, the shared boundaries are already
33480  // in charge of performing the connection (it will be required
33481  // to disabled the connection) with the original boundary
33482 
33483  } // else if (!connecting_to_an_overlaped_boundary)
33484 
33485  } // if (!connecting_to_an_split_boundary)
33486 #ifdef OOMPH_HAS_MPI
33487  else
33488  {
33489  // If the boundary was split then we need to look for the vertex
33490  // in the sub-polylines
33491 
33492  // Get the sub-polylines vector
33493  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33494  this->boundary_subpolylines(dst_bnd_id_initial);
33495 
33496  // Get the number of sub-polylines
33497  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33498 #ifdef PARANOID
33499  if (nsub_poly <= 1)
33500  {
33501  std::ostringstream error_message;
33502  error_message << "The boundary (" << dst_bnd_id_initial << ") was "
33503  << "marked to be splitted but\n"
33504  << "there are only (" << nsub_poly << ") polylines to "
33505  << "represent it.\n";
33506  throw OomphLibError(
33507  error_message.str(),
33508  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33509  OOMPH_EXCEPTION_LOCATION);
33510  } // if (nsub_poly <= 1)
33511 #endif
33512  // We need to check if the boundary is marked to be overlaped by
33513  // a shared boundary, if that is the case we need to check for
33514  // each indivual subpolyline, and for those overlaped by a
33515  // shared polyline do nothing, the shared polylines have already
33516  // deal with these connections
33517 
33518  // ... check if the boundary is marked to be overlaped by
33519  // a shared boundary
33520  if (!connecting_to_an_overlaped_boundary)
33521  {
33522  // The boundary is not overlapped by shared boundaries, we can
33523  // work without checking the subpolylines individually (non of
33524  // them are overlapped by a shared boundary)
33525 
33526  // Look for the vertex number to connect on each of the
33527  // subpolyines
33528  for (unsigned isub = 0; isub < nsub_poly; isub++)
33529  {
33530  // Assign the pointer to the sub-polyline
33531  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33532  // Search for the vertex in the current sub-polyline
33533  found_vertex_on_dst_boundary_initial =
33534  this->get_connected_vertex_number_on_destination_polyline(
33535  poly_to_connect_pt,
33536  src_vertex_coordinates_initial,
33537  n_vertex_connection_initial);
33538 
33539  // If we have found the vertex to connect then break the
33540  // loop
33541  if (found_vertex_on_dst_boundary_initial)
33542  {
33543  // But first save the subpoly number (chunk), that will be
33544  // used to perform the connection
33545  sub_poly_to_connect = isub;
33546  break;
33547  } // if (found_vertex_on_dst_boundary_initial)
33548 
33549  } // for (isub < nsub_poly)
33550 
33551  } // if (!connecting_to_an_overlaped_boundary)
33552  else
33553  {
33554  // If connecting to an overlapped boundary then we ignore the
33555  // subpolylines overlapped by shared boundaries and only look
33556  // on the sub-polylines that are not marked as being overlaped
33557  // by shared boundaries
33558 
33559  // Look for the vertex number to connect on each of the
33560  // subpolyines
33561  for (unsigned isub = 0; isub < nsub_poly; isub++)
33562  {
33563  // Only work with those sub-polylines that are not overlaped
33564  // by shared boundaries
33565  if (!this->boundary_marked_as_shared_boundary(dst_bnd_id_initial,
33566  isub))
33567  {
33568  // Assign the pointer to the sub-polyline
33569  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33570 
33571  // Search for the vertex in the current sub-polyline
33572  found_vertex_on_dst_boundary_initial =
33573  this->get_connected_vertex_number_on_destination_polyline(
33574  poly_to_connect_pt,
33575  src_vertex_coordinates_initial,
33576  n_vertex_connection_initial);
33577 
33578  // Was the vertex found?
33579  if (found_vertex_on_dst_boundary_initial)
33580  {
33581  // But first save the subpoly number (chunk), that will
33582  // be used to perform the connection
33583  sub_poly_to_connect = isub;
33584  break;
33585  } // if (found_vertex_on_dst_boundary_initial)
33586 
33587  } // if (not overlaped by shared boundary)
33588 
33589  } // for (isub < nsub_poly)
33590 
33591  } // else if (!connecting_to_an_overlaped_boundary)
33592 
33593  } // else if (!connecting_to_an_split_boundary)
33594 #endif // #ifdef OOMPH_HAS_MPI
33595 
33596  // If not found it may be that the connection information is
33597  // inverted
33598  if (!found_vertex_on_dst_boundary_initial)
33599  {
33600  // Is the mesh distributed?
33601 #ifdef OOMPH_HAS_MPI
33602  if (this->is_mesh_distributed())
33603  {
33604  // If the mesh is distributed and the vertex number was not
33605  // found, that means that the boundary (or vertex) to connect
33606  // in the destination boundary is not in the current
33607  // processor. In that case suspend the connection
33608  polyline_pt->suspend_initial_vertex_connected();
33609  // Add the polyline to the vector of polylines whose
33610  // connection will be resumed at the end of the adaptation
33611  // process
33612  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33613  // The shared boundaries are marked to connect to the initial
33614  // vertex of the polyline (remember that a shared boundary
33615  // stops adding nodes when it finds a node on an original
33616  // boundary) -- The initial vertex is now a base node
33617  }
33618  else
33619 #endif // #ifdef OOMPH_HAS_MPI
33620  {
33621 #ifdef PARANOID
33622  // If not found then there is a problem with the vertices
33623  // Get the associated boundary id of the current polyline
33624  const unsigned bnd_id = polyline_pt->boundary_id();
33625  std::ostringstream error_message;
33626  error_message
33627  << "INITIAL VERTEX CONNECTION\n"
33628  << "It was not possible to find the associated "
33629  << "vertex number on the destination boundary\n"
33630  << "The current boundary (" << bnd_id << ") is marked to have"
33631  << "a connection at the\nINITIAL vertex ("
33632  << src_vertex_coordinates_initial[0] << ","
33633  << src_vertex_coordinates_initial[1] << ")\n"
33634  << "with boundary (" << dst_bnd_id_initial << ")\n"
33635  << "This is the list of vertices on the destination boundary\n";
33636  // Get the pointer to the associated polyline by using the
33637  // boundary id
33638  TriangleMeshPolyLine* dst_polyline =
33639  this->boundary_polyline_pt(dst_bnd_id_initial);
33640  // The number of vertices on the destination boundary
33641  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33642  // Loop over the vertices print them
33643  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33644  {
33645  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33646  error_message << "Vertex#(i): (" << current_vertex[0] << ", "
33647  << current_vertex[1] << ")\n";
33648  }
33649  throw OomphLibError(
33650  error_message.str(),
33651  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33652  OOMPH_EXCEPTION_LOCATION);
33653 #endif
33654 
33655  } // else if (this->is_mesh_distributed())
33656 
33657  } // if (!found_vertex_on_dst_boundary_initial)
33658  else
33659  {
33660  // Set the vertex number on the destination boundary
33661  polyline_pt->initial_vertex_connected_n_vertex() =
33662  n_vertex_connection_initial;
33663 
33664  // Set the chunk number on the destination boundary
33665  polyline_pt->initial_vertex_connected_n_chunk() = sub_poly_to_connect;
33666 
33667  } // else if (!found_vertex_on_dst_boundary_initial)
33668 
33669  } // if (polyline_pt->is_initial_vertex_connected())
33670 
33671  // ------------------------------------------------------------------
33672  // Is the final vertex connected?
33673  if (polyline_pt->is_final_vertex_connected())
33674  {
33675  // The pointer to the boundary to connect
33676  TriangleMeshPolyLine* poly_to_connect_pt = 0;
33677 
33678  // Get the boundary id of the destination/connected boundary
33679  const unsigned dst_bnd_id_final =
33680  polyline_pt->final_vertex_connected_bnd_id();
33681 
33682  // Get the final vertex on the current boundary
33683  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33684  Vector<double> src_vertex_coordinates_final =
33685  polyline_pt->vertex_coordinate(tmp_n_vertices - 1);
33686 
33687 
33688 #ifdef PARANOID
33689  // Is the mesh distributed?
33690 #ifdef OOMPH_HAS_MPI
33691  if (this->is_mesh_distributed())
33692  {
33693  // Get the initial shared boundary id
33694  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33695  // Is the boundary to connect a shared boundary
33696  if (dst_bnd_id_final >= init_shd_bnd_id)
33697  {
33698  // Get the current polyline original boundary id
33699  const unsigned bnd_id = polyline_pt->boundary_id();
33700  std::ostringstream error_message;
33701  error_message
33702  << "FINAL VERTEX CONNECTION\n"
33703  << "The current original boundary is trying to connect to a\n"
33704  << "shared boundary, this is not allowed. In this case the\n"
33705  << "shared boundary should be the one that connects with the\n"
33706  << "original boundary\n"
33707  << "The current boundary (" << bnd_id << ") is marked to have "
33708  << "a connection at the\nFINAL vertex ("
33709  << src_vertex_coordinates_final[0] << ","
33710  << src_vertex_coordinates_final[1] << ")\n"
33711  << "with boundary (" << dst_bnd_id_final << ")\n"
33712  << "This is the list of vertices on the destination boundary\n";
33713  // Get the pointer to the associated polyline by using the
33714  // boundary id
33715  TriangleMeshPolyLine* dst_polyline =
33716  this->boundary_polyline_pt(dst_bnd_id_final);
33717  // The number of vertices on the destination boundary
33718  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33719  // Loop over the vertices print them
33720  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33721  {
33722  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33723  error_message << "Vertex#(" << i << "): (" << current_vertex[0]
33724  << ", " << current_vertex[1] << ")\n";
33725  }
33726  throw OomphLibError(
33727  error_message.str(),
33728  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33729  OOMPH_EXCEPTION_LOCATION);
33730  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33731 
33732  } // if (this->is_mesh_distributed())
33733 #endif // #ifdef OOMPH_HAS_MPI
33734 
33735 #endif // #ifdef PARANOID
33736 
33737  // Flag to indicate if the vertex was found on the destination
33738  // boundary
33739  bool found_vertex_on_dst_boundary_final = false;
33740 
33741  // Flag that stores the chunk number to connect (only used in
33742  // distributed meshes)
33743  unsigned sub_poly_to_connect = 0;
33744 
33745  // Store the vertex number on the destination boundary
33746  unsigned n_vertex_connection_final = 0;
33747 
33748  // Flags only used in a distributed mesh
33749  // ----------------------------------------
33750  // Flag to indicate we are trying to connect to an split boundary
33751  bool connecting_to_an_split_boundary = false;
33752 
33753  // Flag to indicate we are trying to connecto to an internal
33754  // boundary that is overlaped by a shared boundary)
33755  bool connecting_to_an_overlaped_boundary = false;
33756 
33757 #ifdef OOMPH_HAS_MPI
33758  if (this->is_mesh_distributed())
33759  {
33760  // We can only connect to an original boundary, check if the
33761  // boundary was splitted during the distribution process to
33762  // consider all the chunks (sub-polylines) of the boundary
33763  if (this->boundary_was_splitted(dst_bnd_id_final))
33764  {
33765  connecting_to_an_split_boundary = true;
33766  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33767 
33768  // Check if the destination boundary, or any of its chunks is
33769  // marked to be overlapped by a shared boundary, if that is the
33770  // case we can only connect to the chunks that are not
33771  // overlapped by shared boundaries (the shared boundaries are in
33772  // charge of generating the connections with original boundaries
33773  // and with themselves)
33774  if (connecting_to_an_split_boundary)
33775  {
33776  // Get the number of chucks that represent the destination
33777  // boundary
33778  const unsigned n_sub_poly =
33779  this->nboundary_subpolylines(dst_bnd_id_final);
33780  // Now loop over the chunks of the destination boundary and if
33781  // any of them is marked to be overlaped by a shared boundary
33782  // then set the flag and break the loop
33783  for (unsigned ii = 0; ii < n_sub_poly; ii++)
33784  {
33785  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33786  {
33787  // Mark the boundary as being overlaped by a shared
33788  // boundary
33789  connecting_to_an_overlaped_boundary = true;
33790  // Break, no need to look for more overlapings
33791  break;
33792  } // if (boundary_marked_as_shared_boundary(...))
33793  } // for (ii < n_sub_poly)
33794  } // if (connecting_to_an_split_boundary)
33795  else
33796  {
33797  // If not connecting to an split boundary then check if the
33798  // whole destination boundary is overlaped by an internal
33799  // boundary
33800  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33801  {
33802  // Mark the boundary as being overlaped by a shared boundary
33803  connecting_to_an_overlaped_boundary = true;
33804  } // if (boundary_marked_as_shared_boundary(...))
33805  } // else if (connecting_to_an_split_boundary)
33806 
33807  } // if (this->is_mesh_distributed())
33808 
33809 #endif // #ifdef OOMPH_HAS_MPI
33810 
33811  // If we are connecting neither to an split boundary nor an
33812  // overlaped boundary then get the pointer to the original
33813  // boundary
33814  if (!(connecting_to_an_split_boundary ||
33815  connecting_to_an_overlaped_boundary))
33816  {
33817  // Get the polyline pointer representing the destination
33818  // boundary
33819  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33820  } // else if (NOT split, NOT overlaped)
33821 
33822  // Now look for the vertex number on the destination boundary(ies)
33823  // -- in case that the boundary was split ---
33824 
33825  // Do not check for same orientation, that was previously worked
33826  // by interchanging the connections boundaries (if necessary)
33827 
33828  // If the boundary was not split then ...
33829  if (!connecting_to_an_split_boundary)
33830  {
33831  // ... check if the boundary is marked to be overlaped by
33832  // a shared boundary
33833  if (!connecting_to_an_overlaped_boundary)
33834  {
33835  // If that is not the case then we can safely look for the
33836  // vertex number on the destination boundary
33837  found_vertex_on_dst_boundary_final =
33838  this->get_connected_vertex_number_on_destination_polyline(
33839  poly_to_connect_pt,
33840  src_vertex_coordinates_final,
33841  n_vertex_connection_final);
33842 
33843  } // if (!connecting_to_an_overlaped_boundary)
33844  else
33845  {
33846  // If the whole boundary is marked to be overlaped by a shared
33847  // boundary then do nothing, the shared boundaries are already
33848  // in charge of performing the connection (it will be required
33849  // to disabled the connection) with the original boundary
33850 
33851  } // else if (!connecting_to_an_overlaped_boundary)
33852 
33853  } // if (!connecting_to_an_split_boundary)
33854 #ifdef OOMPH_HAS_MPI
33855  else
33856  {
33857  // If the boundary was split then we need to look for the vertex
33858  // in the sub-polylines
33859 
33860  // Get the sub-polylines vector
33861  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33862  this->boundary_subpolylines(dst_bnd_id_final);
33863 
33864  // Get the number of sub-polylines
33865  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33866 #ifdef PARANOID
33867  if (nsub_poly <= 1)
33868  {
33869  std::ostringstream error_message;
33870  error_message << "The boundary (" << dst_bnd_id_final << ") was "
33871  << "marked to be splitted but\n"
33872  << "there are only (" << nsub_poly << ") polylines to "
33873  << "represent it.\n";
33874  throw OomphLibError(
33875  error_message.str(),
33876  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33877  OOMPH_EXCEPTION_LOCATION);
33878  } // if (nsub_poly <= 1)
33879 #endif
33880  // We need to check if the boundary is marked to be overlaped by
33881  // a shared boundary, if that is the case we need to check for
33882  // each indivual subpolyline, and for those overlaped by a
33883  // shared polyline do nothing, the shared polylines have already
33884  // deal with these connections
33885 
33886  // ... check if the boundary is marked to be overlaped by
33887  // a shared boundary
33888  if (!connecting_to_an_overlaped_boundary)
33889  {
33890  // The boundary is not overlapped by shared boundaries, we can
33891  // work without checking the subpolylines individually (non of
33892  // them are overlapped by a shared boundary)
33893 
33894  // Look for the vertex number to connect on each of the
33895  // subpolyines
33896  for (unsigned isub = 0; isub < nsub_poly; isub++)
33897  {
33898  // Assign the pointer to the sub-polyline
33899  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33900  // Search for the vertex in the current sub-polyline
33901  found_vertex_on_dst_boundary_final =
33902  this->get_connected_vertex_number_on_destination_polyline(
33903  poly_to_connect_pt,
33904  src_vertex_coordinates_final,
33905  n_vertex_connection_final);
33906 
33907  // If we have found the vertex to connect then break the
33908  // loop
33909  if (found_vertex_on_dst_boundary_final)
33910  {
33911  // But first save the subpoly number (chunk), that will be
33912  // used to perform the connection
33913  sub_poly_to_connect = isub;
33914  break;
33915  } // if (found_vertex_on_dst_boundary_initial)
33916 
33917  } // for (isub < nsub_poly)
33918 
33919  } // if (!connecting_to_an_overlaped_boundary)
33920  else
33921  {
33922  // If connecting to an overlapped boundary then we ignore the
33923  // subpolylines overlapped by shared boundaries and only look
33924  // on the sub-polylines that are not marked as being overlaped
33925  // by shared boundaries
33926 
33927  // Look for the vertex number to connect on each of the
33928  // subpolyines
33929  for (unsigned isub = 0; isub < nsub_poly; isub++)
33930  {
33931  // Only work with those sub-polylines that are not overlaped
33932  // by shared boundaries
33933  if (!this->boundary_marked_as_shared_boundary(dst_bnd_id_final,
33934  isub))
33935  {
33936  // Assign the pointer to the sub-polyline
33937  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33938 
33939  // Search for the vertex in the current sub-polyline
33940  found_vertex_on_dst_boundary_final =
33941  this->get_connected_vertex_number_on_destination_polyline(
33942  poly_to_connect_pt,
33943  src_vertex_coordinates_final,
33944  n_vertex_connection_final);
33945 
33946  // Was the vertex found?
33947  if (found_vertex_on_dst_boundary_final)
33948  {
33949  // But first save the subpoly number (chunk), that will
33950  // be used to perform the connection
33951  sub_poly_to_connect = isub;
33952  break;
33953  } // if (found_vertex_on_dst_boundary_final)
33954 
33955  } // if (not overlaped by shared boundary)
33956 
33957  } // for (isub < nsub_poly)
33958 
33959  } // else if (!connecting_to_an_overlaped_boundary)
33960 
33961  } // else if (!connecting_to_an_split_boundary)
33962 #endif // #ifdef OOMPH_HAS_MPI
33963 
33964  // If not found it may be that the connection information is
33965  // inverted
33966  if (!found_vertex_on_dst_boundary_final)
33967  {
33968  // Is the mesh distributed?
33969 #ifdef OOMPH_HAS_MPI
33970  if (this->is_mesh_distributed())
33971  {
33972  // If the mesh is distributed and the vertex number was not
33973  // found, that means that the boundary (or vertex) to connect
33974  // in the destination boundary is not in the current
33975  // processor. In that suspend the connection
33976  polyline_pt->suspend_final_vertex_connected();
33977  // Add the polyline to the vector of polylines whose
33978  // connection will be resumed at the end of the adaptation
33979  // process
33980  resume_final_connection_polyline_pt.push_back(polyline_pt);
33981  // The shared boundaries are marked to connect to the final
33982  // vertex of the polyline (remember that a shared boundary
33983  // stops adding nodes when it finds a node on an original
33984  // boundary) -- The final vertex is now a base node
33985  } // if (this->is_mesh_distributed())
33986  else
33987 #endif // #ifdef OOMPH_HAS_MPI
33988  {
33989 #ifdef PARANOID
33990  // If not found then there is a problem with the vertices
33991  // Get the associated boundary id of the current polyline
33992  const unsigned bnd_id = polyline_pt->boundary_id();
33993  std::ostringstream error_message;
33994  error_message
33995  << "FINAL VERTEX CONNECTION\n"
33996  << "It was not possible to find the associated "
33997  << "vertex number on the destination boundary\n"
33998  << "The current boundary (" << bnd_id << ") is marked to have "
33999  << "a connection at the\nFINAL vertex ("
34000  << src_vertex_coordinates_final[0] << ","
34001  << src_vertex_coordinates_final[1] << ")\n"
34002  << "with boundary (" << dst_bnd_id_final << ")\n"
34003  << "This is the list of vertices on the destination boundary\n";
34004  // Get the pointer to the associated polyline by using the
34005  // boundary id
34006  TriangleMeshPolyLine* dst_polyline =
34007  this->boundary_polyline_pt(dst_bnd_id_final);
34008  // The number of vertices on the destination boundary
34009  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
34010  // Loop over the vertices print them
34011  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
34012  {
34013  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
34014  error_message << "Vertex#(" << i << "): (" << current_vertex[0]
34015  << ", " << current_vertex[1] << ")\n";
34016  }
34017  throw OomphLibError(
34018  error_message.str(),
34019  "RefineableTriangleMesh::restore_polyline_connections_helper()",
34020  OOMPH_EXCEPTION_LOCATION);
34021 #endif
34022  } // else if (this->is_mesh_distributed())
34023 
34024  } // if (!found_vertex_on_dst_boundary_final)
34025  else
34026  {
34027  // Set the vertex number on the destination boundary
34028  polyline_pt->final_vertex_connected_n_vertex() =
34029  n_vertex_connection_final;
34030 
34031  // Set the chunk number on the destination boundary
34032  polyline_pt->final_vertex_connected_n_chunk() = sub_poly_to_connect;
34033 
34034  } // else if (!found_vertex_on_dst_boundary_final)
34035 
34036  } // if (polyline_pt->is_final_vertex_connected())
34037  }
34038 
34039  //=========================================================================
34040  /// \short Resume the boundary connections that may have been
34041  /// suspended because the destination boundary is no part of the
34042  /// domain. The connections are no permanently suspended because if
34043  /// load balance takes place the destination boundary may be part of
34044  /// the new domain representation therefore the connection would
34045  /// exist
34046  //=========================================================================
34047  template<class ELEMENT>
34049  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
34050  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
34051  {
34052  // Get the number of polylines that require to resume the connection
34053  // at the initial vertex
34054  const unsigned n_initial_poly =
34055  resume_initial_connection_polyline_pt.size();
34056  // Loop over the polylines that require to resume the connection
34057  // at the initial vertex
34058  for (unsigned p = 0; p < n_initial_poly; p++)
34059  {
34060  // Get the polyline
34061  TriangleMeshPolyLine* tmp_poly_pt =
34062  resume_initial_connection_polyline_pt[p];
34063  // Resume the connection with the initial vertex
34064  tmp_poly_pt->resume_initial_vertex_connected();
34065  } // for (p < n_initial_poly)
34066 
34067  // Get the number of polylines that require to resume the connection
34068  // at the final vertex
34069  const unsigned n_final_poly = resume_final_connection_polyline_pt.size();
34070  // Loop over the polylines that require to resume the connection at
34071  // the final vertex
34072  for (unsigned p = 0; p < n_final_poly; p++)
34073  {
34074  // Get the polyline
34075  TriangleMeshPolyLine* tmp_poly_pt =
34076  resume_final_connection_polyline_pt[p];
34077  // Resume the connection with the final vertex
34078  tmp_poly_pt->resume_final_vertex_connected();
34079  } // for (p < n_final_poly)
34080 
34081  // Clear the storage
34082  resume_initial_connection_polyline_pt.clear();
34083  resume_final_connection_polyline_pt.clear();
34084  }
34085 
34086  //=========================================================================
34087  /// \short Gets the associated vertex number according to the vertex
34088  /// coordinates on the destination boundary
34089  //=========================================================================
34090  template<class ELEMENT>
34093  Vector<double>& vertex_coordinates,
34094  const unsigned& dst_bnd_id,
34095  unsigned& vertex_number)
34096  {
34097  bool found_associated_vertex_number = false;
34098 
34099  // Get the pointer to the associated polyline by using the boundary id
34100  TriangleMeshPolyLine* dst_polyline = this->boundary_polyline_pt(dst_bnd_id);
34101 
34102  const unsigned n_vertices = dst_polyline->nvertex();
34103 
34104  // Loop over the vertices and return the closest vertex
34105  // to the given vertex coordinates
34106  for (unsigned i = 0; i < n_vertices; i++)
34107  {
34108  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
34109 
34110  double error = (vertex_coordinates[0] - current_vertex[0]) *
34111  (vertex_coordinates[0] - current_vertex[0]) +
34112  (vertex_coordinates[1] - current_vertex[1]) *
34113  (vertex_coordinates[1] - current_vertex[1]);
34114 
34115  error = sqrt(error);
34116 
34117  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
34118  {
34119  vertex_number = i;
34120  found_associated_vertex_number = true;
34121  break;
34122  }
34123  }
34124 
34125  return found_associated_vertex_number;
34126  }
34127 
34128  //=========================================================================
34129  /// \short Helper function that updates the input polygon's PSLG
34130  /// by using the end-points of elements from FaceMesh(es) that are
34131  /// constructed for the boundaries associated with the segments of the
34132  /// polygon. Optional boolean is used to run it as test only (if
34133  /// true is specified as input) in which case polygon isn't actually
34134  /// modified. Returned boolean indicates if polygon was (or would have
34135  /// been -- if called with check_only=false) changed.
34136  //=========================================================================
34137  template<class ELEMENT>
34139  TriangleMeshPolygon* polygon_pt, const bool& check_only)
34140  {
34141 #ifdef PARANOID
34142  // If the mesh is marked as distributed this method can not be
34143  // called since there is no guarantee of creating (distributed)
34144  // meshes that match in the number and position of nodes at their
34145  // shared boundaries. The only exececption is when called with
34146  // check_only=true, since no boundary updating is performed
34147  if (this->is_mesh_distributed() && !check_only)
34148  {
34149  std::stringstream error_message;
34150  error_message
34151  << "The updating of polygons of a distributed mesh can ONLY be\n"
34152  << "performed using the element's area associated to the halo(ed)\n"
34153  << "elements.\n"
34154  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34155  << "option if you are working with a distributed mesh, OR\n"
34156  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34157  << "if the mesh is marked as distributed\n\n";
34158  throw OomphLibError(
34159  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
34160  } // if (this->is_mesh_distributed())
34161 #endif
34162 
34163  // Boolean that indicates whether an actual update of the polygon
34164  // was performed or not
34165  bool unrefinement_was_performed = false;
34166  bool refinement_was_performed = false;
34167  bool max_length_applied = false;
34168 
34169  // Loop over the number of polylines
34170  const unsigned n_polyline = polygon_pt->npolyline();
34171 
34172  // Get face mesh representation of all polylines, possibly
34173  // with segments re-distributed to maintain an approximately
34174  // even sub-division of the polygon
34175  Vector<Mesh*> face_mesh_pt;
34176  get_face_mesh_representation(polygon_pt, face_mesh_pt);
34177 
34178  // Create vertices for the polylines by using the vertices
34179  // of the FaceElements
34180  Vector<double> vertex_coord(3); // zeta,x,y
34181  Vector<double> bound_left(1);
34182  Vector<double> bound_right(1);
34183 
34184  for (unsigned p = 0; p < n_polyline; p++)
34185  {
34186  // Set of coordinates that will be placed on the boundary
34187  // Set entries are ordered on first entry in vector which stores
34188  // the boundary coordinate so the vertices come out in order!
34189  std::set<Vector<double>> vertex_nodes;
34190 
34191  // Get the boundary id
34192  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
34193 
34194  // Get the chunk number
34195  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
34196 
34197  // Loop over the face elements (ordered) and add their vertices
34198  unsigned n_face_element = face_mesh_pt[p]->nelement();
34199  for (unsigned e = 0; e < n_face_element; ++e)
34200  {
34201  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34202 
34203 #ifdef OOMPH_HAS_MPI
34204  // Only work with non-halo elements if the mesh is distributed
34205  if (this->is_mesh_distributed() && el_pt->is_halo())
34206  {
34207  continue;
34208  }
34209 #endif
34210 
34211  unsigned n_node = el_pt->nnode();
34212 
34213  // Add the left-hand node to the set:
34214 
34215  // Boundary coordinate
34216  el_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
34217  vertex_coord[0] = bound_left[0];
34218 
34219  // Actual coordinates
34220  for (unsigned i = 0; i < 2; i++)
34221  {
34222  vertex_coord[i + 1] = el_pt->node_pt(0)->x(i);
34223  }
34224  vertex_nodes.insert(vertex_coord);
34225 
34226  // Add the right-hand nodes to the set:
34227 
34228  // Boundary coordinate
34229  el_pt->node_pt(n_node - 1)
34230  ->get_coordinates_on_boundary(bound, bound_right);
34231  vertex_coord[0] = bound_right[0];
34232 
34233  // Actual coordinates
34234  for (unsigned i = 0; i < 2; i++)
34235  {
34236  vertex_coord[i + 1] = el_pt->node_pt(n_node - 1)->x(i);
34237  }
34238  vertex_nodes.insert(vertex_coord);
34239  }
34240 
34241  // Now turn into vector for ease of handling...
34242  unsigned n_poly_vertex = vertex_nodes.size();
34243  Vector<Vector<double>> tmp_vector_vertex_node(n_poly_vertex);
34244  unsigned count = 0;
34245  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
34246  it != vertex_nodes.end();
34247  ++it)
34248  {
34249  tmp_vector_vertex_node[count].resize(3);
34250  tmp_vector_vertex_node[count][0] = (*it)[0];
34251  tmp_vector_vertex_node[count][1] = (*it)[1];
34252  tmp_vector_vertex_node[count][2] = (*it)[2];
34253  ++count;
34254  }
34255 
34256  // Size of the vector
34257  unsigned n_vertex = tmp_vector_vertex_node.size();
34258 
34259  // Tolerance below which the middle point can be deleted
34260  // (ratio of deflection to element length)
34261  double unrefinement_tolerance =
34262  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
34263 
34264  //------------------------------------------------------
34265  // Unrefinement
34266  //------------------------------------------------------
34267  if (unrefinement_tolerance > 0.0 && n_vertex >= 3)
34268  {
34269  unrefinement_was_performed = unrefine_boundary(bound,
34270  chunk,
34271  tmp_vector_vertex_node,
34272  unrefinement_tolerance,
34273  check_only);
34274 
34275  // In this case the "unrefinement_was_performed" variable
34276  // tell us if the update had been performed when calling
34277  // with check_oly=false
34278  if (check_only && unrefinement_was_performed)
34279  {
34280  // Cleanup (but only the elements -- the nodes still exist in
34281  // the bulk mesh!
34282  for (unsigned p = 0; p < n_polyline; p++)
34283  {
34284  face_mesh_pt[p]->flush_node_storage();
34285  delete face_mesh_pt[p];
34286  }
34287  return true;
34288  }
34289 
34290  } // end of unrefinement
34291 
34292  // Do not perform refinement if there are no more than two vertices
34293  // New size of the vector
34294  n_vertex = tmp_vector_vertex_node.size();
34295 
34296  //------------------------------------------------
34297  // Refinement
34298  //------------------------------------------------
34299  double refinement_tolerance =
34300  polygon_pt->polyline_pt(p)->refinement_tolerance();
34301  if (refinement_tolerance > 0.0 && n_vertex >= 2)
34302  {
34303  refinement_was_performed = refine_boundary(face_mesh_pt[p],
34304  tmp_vector_vertex_node,
34305  refinement_tolerance,
34306  check_only);
34307 
34308  // In this case the "refinement_was_performed" variable
34309  // tell us if the update had been performed when calling
34310  // with check_only=false
34311  if (check_only && refinement_was_performed)
34312  {
34313  // Cleanup (but only the elements -- the nodes still exist in
34314  // the bulk mesh!
34315  for (unsigned p = 0; p < n_polyline; p++)
34316  {
34317  face_mesh_pt[p]->flush_node_storage();
34318  delete face_mesh_pt[p];
34319  }
34320  return true;
34321  }
34322 
34323  } // end refinement
34324 
34325  // Do not perform maximum length constraint if there are no more than
34326  // two vertices
34327  // New size of the vector
34328  n_vertex = tmp_vector_vertex_node.size();
34329 
34330  //------------------------------------------------
34331  // Maximum length constrait
34332  //-----------------------------------------------
34333  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34334  if (maximum_length > 0.0 && n_vertex >= 2)
34335  {
34336  max_length_applied = apply_max_length_constraint(
34337  face_mesh_pt[p], tmp_vector_vertex_node, maximum_length);
34338 
34339  // In this case the max length criteria was applied, check if
34340  // check_only=false
34341  if (check_only && max_length_applied)
34342  {
34343  // Cleanup (but only the elements -- the nodes still exist in
34344  // the bulk mesh!
34345  for (unsigned p = 0; p < n_polyline; p++)
34346  {
34347  face_mesh_pt[p]->flush_node_storage();
34348  delete face_mesh_pt[p];
34349  }
34350  return true;
34351  }
34352  }
34353 
34354  // For further processing the three-dimensional vector
34355  // has to be reduced to a two-dimensional vector
34356  n_vertex = tmp_vector_vertex_node.size();
34357  Vector<Vector<double>> vector_vertex_node(n_vertex);
34358 
34359  for (unsigned i = 0; i < n_vertex; i++)
34360  {
34361  vector_vertex_node[i].resize(2);
34362  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
34363  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
34364  }
34365 
34366 #ifdef OOMPH_HAS_MPI
34367  // Only perform this checking if the mesh is not distributed. When
34368  // the mesh is distributed the polylines continuity is addressed in
34369  // the sort_polylines_helper() method
34370  if (!this->is_mesh_distributed())
34371 #endif
34372  {
34373  if ((p > 0) && !check_only)
34374  {
34375  // Final end point of previous line
34376  Vector<double> final_vertex_of_previous_segment;
34377  unsigned n_prev_vertex =
34378  polygon_pt->curve_section_pt(p - 1)->nvertex();
34379  final_vertex_of_previous_segment =
34380  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
34381  1);
34382 
34383  unsigned prev_seg_boundary_id =
34384  polygon_pt->curve_section_pt(p - 1)->boundary_id();
34385 
34386  // Find the error between the final vertex of the previous
34387  // line and the first vertex of the current line
34388  double error = 0.0;
34389  for (unsigned i = 0; i < 2; i++)
34390  {
34391  const double dist = final_vertex_of_previous_segment[i] -
34392  (*vector_vertex_node.begin())[i];
34393  error += dist * dist;
34394  }
34395  error = sqrt(error);
34396 
34397  // If the error is bigger than the tolerance then
34398  // we probably need to reverse, but better check
34399  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34400  {
34401  // Find the error between the final vertex of the previous
34402  // line and the last vertex of the current line
34403  double rev_error = 0.0;
34404  for (unsigned i = 0; i < 2; i++)
34405  {
34406  const double dist = final_vertex_of_previous_segment[i] -
34407  (*--vector_vertex_node.end())[i];
34408  rev_error += dist * dist;
34409  }
34410  rev_error = sqrt(rev_error);
34411 
34412  if (rev_error >
34413  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34414  {
34415  // It could be possible that the first segment be reversed and we
34416  // did not notice it because this check does not apply for the
34417  // first segment. We can verify if the first segment is reversed
34418  // by using the vertex number 1
34419  if (p == 1)
34420  {
34421  // Initial end point of previous line
34422  Vector<double> initial_vertex_of_previous_segment;
34423 
34424  initial_vertex_of_previous_segment =
34425  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
34426 
34427  unsigned prev_seg_boundary_id =
34428  polygon_pt->curve_section_pt(p - 1)->boundary_id();
34429 
34430  // Find the error between the initial vertex of the previous
34431  // line and the first vertex of the current line
34432  double error = 0.0;
34433  for (unsigned i = 0; i < 2; i++)
34434  {
34435  const double dist = initial_vertex_of_previous_segment[i] -
34436  (*vector_vertex_node.begin())[i];
34437  error += dist * dist;
34438  }
34439  error = sqrt(error); // Reversed only the previous one
34440 
34441  // If the error is bigger than the tolerance then
34442  // we probably need to reverse, but better check
34443  if (error >
34444  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34445  {
34446  // Find the error between the final vertex of the previous
34447  // line and the last vertex of the current line
34448  double rev_error = 0.0;
34449  for (unsigned i = 0; i < 2; i++)
34450  {
34451  const double dist = initial_vertex_of_previous_segment[i] -
34452  (*--vector_vertex_node.end())[i];
34453  rev_error += dist * dist;
34454  }
34455  rev_error =
34456  sqrt(rev_error); // Reversed both the current one and
34457  // the previous one
34458 
34459  if (rev_error >
34460  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34461  {
34462  std::ostringstream error_stream;
34463  error_stream
34464  << "The distance between the first node of the current\n"
34465  << "line segment (boundary " << bound
34466  << ") and either end of "
34467  << "the previous line segment\n"
34468  << "(boundary " << prev_seg_boundary_id
34469  << ") is bigger than "
34470  << "the desired tolerance "
34471  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34472  << ".\n"
34473  << "This suggests that the polylines defining the "
34474  "polygonal\n"
34475  << "representation are not properly ordered.\n"
34476  << "Fail on last vertex of polyline: ("
34477  << prev_seg_boundary_id
34478  << ") and\nfirst vertex of polyline (" << bound
34479  << ").\nThis should have failed when first trying to "
34480  << "construct the\npolygon.\n";
34481  throw OomphLibError(error_stream.str(),
34482  OOMPH_CURRENT_FUNCTION,
34483  OOMPH_EXCEPTION_LOCATION);
34484  }
34485  else
34486  {
34487  // Reverse both
34488  // Reverse the current vector to line up with the previous
34489  // one
34490  std::reverse(vector_vertex_node.begin(),
34491  vector_vertex_node.end());
34492 
34493  polygon_pt->polyline_pt(p - 1)->reverse();
34494  }
34495  }
34496  else
34497  {
34498  // Reverse the previous one
34499  polygon_pt->polyline_pt(p - 1)->reverse();
34500  }
34501 
34502  } // if p == 1
34503  else
34504  {
34505  std::ostringstream error_stream;
34506  error_stream
34507  << "The distance between the first node of the current\n"
34508  << "line segment (boundary " << bound
34509  << ") and either end of "
34510  << "the previous line segment\n"
34511  << "(boundary " << prev_seg_boundary_id
34512  << ") is bigger than the "
34513  << "desired tolerance "
34514  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34515  << ".\n"
34516  << "This suggests that the polylines defining the polygonal\n"
34517  << "representation are not properly ordered.\n"
34518  << "Fail on last vertex of polyline: ("
34519  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
34520  << bound << ").\n"
34521  << "This should have failed when first trying to construct "
34522  "the\n"
34523  << "polygon.\n";
34524  throw OomphLibError(error_stream.str(),
34525  OOMPH_CURRENT_FUNCTION,
34526  OOMPH_EXCEPTION_LOCATION);
34527  }
34528  }
34529  else
34530  {
34531  // Reverse the current vector to line up with the previous one
34532  std::reverse(vector_vertex_node.begin(),
34533  vector_vertex_node.end());
34534  }
34535 
34536  } // first error
34537  } // p > 0
34538  } // is mesh not distributed?
34539 
34540  if (!check_only)
34541  {
34542  // Now update the polyline according to the new vertices
34543  // The new one representation
34544  TriangleMeshPolyLine* tmp_polyline_pt =
34545  new TriangleMeshPolyLine(vector_vertex_node, bound);
34546 
34547  // Create a temporal "curve section" version of the recently created
34548  // polyline
34549  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
34550 
34551  // Establish refinement and unrefinement tolerance
34552  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
34553  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
34554 
34555  // Establish the maximum length constraint
34556  tmp_polyline_pt->set_maximum_length(maximum_length);
34557 
34558  // We pass the connection information from the old polyline to
34559  // the new one
34560  this->copy_connection_information(polygon_pt->polyline_pt(p),
34561  tmp_curve_section_pt);
34562 
34563  // Now update the polyline according to the new vertices but
34564  // first check if the object is allowed to delete the representation
34565  // or if it should be done by other object
34566  bool delete_it_on_destructor = false;
34567 
34568  std::set<TriangleMeshCurveSection*>::iterator it =
34569  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34570 
34571  if (it != this->Free_curve_section_pt.end())
34572  {
34573  this->Free_curve_section_pt.erase(it);
34574  delete polygon_pt->curve_section_pt(p);
34575  delete_it_on_destructor = true;
34576  }
34577 
34578  // ------------------------------------------------------------
34579  // Copying the new representation
34580  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34581 
34582  // Update the Boundary - Polyline map
34583  this->Boundary_curve_section_pt[bound] =
34584  polygon_pt->curve_section_pt(p);
34585 
34586  if (delete_it_on_destructor)
34587  {
34588  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34589  }
34590 
34591  } // if(!check_only)
34592 
34593  } // for (p < n_polyline)
34594 
34595  // Cleanup (but only the elements -- the nodes still exist in
34596  // the bulk mesh!
34597  for (unsigned p = 0; p < n_polyline; p++)
34598  {
34599  face_mesh_pt[p]->flush_node_storage();
34600  delete face_mesh_pt[p];
34601  }
34602 
34603  if (check_only)
34604  {
34605  // if we end up all the way down here, no update of the internal
34606  // boundaries is necessary (in case we only check)
34607  return false;
34608  }
34609  else
34610  {
34611  // if we not only check, but actually perform the update and end up
34612  // all the way down here then we indicate whether an update was performed
34613  // or not
34614  return (unrefinement_was_performed || refinement_was_performed ||
34615  max_length_applied);
34616  }
34617  }
34618 
34619  //=========================================================================
34620  /// \short Helper function that updates the input open curve by using
34621  /// end-points of elements from FaceMesh(es) that are constructed for the
34622  /// boundaries associated with the polylines. Optional boolean is used to
34623  /// run it as test only (if true is specified as input) in which case the
34624  /// polylines are not actually modified. Returned boolean indicates if
34625  /// polylines were (or would have been -- if called with check_only=false)
34626  /// changed.
34627  //=========================================================================
34628  template<class ELEMENT>
34630  TriangleMeshOpenCurve* open_polyline_pt, const bool& check_only)
34631  {
34632 #ifdef PARANOID
34633  // If the mesh is marked as distributed this method can not be
34634  // called since there is no guarantee of creating (distributed)
34635  // meshes that match in the number and position of nodes at their
34636  // shared boundaries. The only exececption is when called with
34637  // check_only=true, since no boundary updating is performed
34638  if (this->is_mesh_distributed() && !check_only)
34639  {
34640  std::stringstream error_message;
34641  error_message
34642  << "The updating of open curves of a distributed mesh can ONLY be\n"
34643  << "performed using the element's area associated to the halo(ed)\n"
34644  << "elements.\n"
34645  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34646  << "option if you are working with a distributed mesh, OR\n"
34647  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34648  << "if the mesh is marked as distributed\n\n";
34649  throw OomphLibError(
34650  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
34651  } // if (this->is_mesh_distributed())
34652 #endif
34653 
34654  // Boolean that indicates whether an actual update of the polylines
34655  // were performed or not
34656  bool unrefinement_was_performed = false;
34657  bool refinement_was_performed = false;
34658  bool max_length_applied = false;
34659 
34660  // Loop over the number of polylines
34661  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34662 
34663  // Get face mesh representation of all polylines, possibly
34664  // with segments re-distributed to maintain an approximately
34665  // even sub-division of the polygon
34666  Vector<Mesh*> face_mesh_pt;
34667  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34668 
34669  // Create vertices for the polylines by using the vertices
34670  // of the FaceElements
34671  Vector<double> vertex_coord(3); // zeta,x,y
34672  Vector<double> bound_left(1);
34673  Vector<double> bound_right(1);
34674 
34675  for (unsigned p = 0; p < n_polyline; p++)
34676  {
34677  // Set of coordinates that will be placed on the boundary
34678  // Set entries are ordered on first entry in vector which stores
34679  // the boundary coordinate so the vertices come out in order!
34680  std::set<Vector<double>> vertex_nodes;
34681 
34682  // Get the boundary id
34683  const unsigned bound =
34684  open_polyline_pt->curve_section_pt(p)->boundary_id();
34685 
34686  // Get the chunk number
34687  const unsigned chunk =
34688  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34689 
34690  // Loop over the face elements (ordered) and add their vertices
34691  unsigned n_face_element = face_mesh_pt[p]->nelement();
34692 
34693  // n_count = 0;
34694  for (unsigned e = 0; e < n_face_element; ++e)
34695  {
34696  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34697  unsigned n_node = el_pt->nnode();
34698 
34699  // Add the left-hand node to the set:
34700 
34701  // Boundary coordinate
34702  el_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
34703  vertex_coord[0] = bound_left[0];
34704 
34705  // Actual coordinates
34706  for (unsigned i = 0; i < 2; i++)
34707  {
34708  vertex_coord[i + 1] = el_pt->node_pt(0)->x(i);
34709  }
34710  vertex_nodes.insert(vertex_coord);
34711 
34712  // Add the right-hand nodes to the set:
34713 
34714  // Boundary coordinate
34715  el_pt->node_pt(n_node - 1)
34716  ->get_coordinates_on_boundary(bound, bound_right);
34717  vertex_coord[0] = bound_right[0];
34718 
34719  // Actual coordinates
34720  for (unsigned i = 0; i < 2; i++)
34721  {
34722  vertex_coord[i + 1] = el_pt->node_pt(n_node - 1)->x(i);
34723  }
34724  vertex_nodes.insert(vertex_coord);
34725  }
34726 
34727  // Now turn into vector for ease of handling...
34728  unsigned n_poly_vertex = vertex_nodes.size();
34729  Vector<Vector<double>> tmp_vector_vertex_node(n_poly_vertex);
34730  unsigned count = 0;
34731  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
34732  it != vertex_nodes.end();
34733  ++it)
34734  {
34735  tmp_vector_vertex_node[count].resize(3);
34736  tmp_vector_vertex_node[count][0] = (*it)[0];
34737  tmp_vector_vertex_node[count][1] = (*it)[1];
34738  tmp_vector_vertex_node[count][2] = (*it)[2];
34739  ++count;
34740  }
34741 
34742  // Size of the vector
34743  unsigned n_vertex = tmp_vector_vertex_node.size();
34744 
34745  // Tolerance below which the middle point can be deleted
34746  // (ratio of deflection to element length)
34747  double unrefinement_tolerance =
34748  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34749 
34750  //------------------------------------------------------
34751  // Unrefinement
34752  //------------------------------------------------------
34753  if (unrefinement_tolerance > 0.0 && n_vertex >= 3)
34754  {
34755  unrefinement_was_performed = unrefine_boundary(bound,
34756  chunk,
34757  tmp_vector_vertex_node,
34758  unrefinement_tolerance,
34759  check_only);
34760 
34761  // In this case the unrefinement_was_performed variable actually
34762  // tell us if the update had been performed when calling
34763  // with check_only=false
34764  if (check_only && unrefinement_was_performed)
34765  {
34766  // Cleanup (but only the elements -- the nodes still exist in
34767  // the bulk mesh!
34768  for (unsigned p = 0; p < n_polyline; p++)
34769  {
34770  face_mesh_pt[p]->flush_node_storage();
34771  delete face_mesh_pt[p];
34772  }
34773  return true;
34774  }
34775 
34776  } // end of unrefinement
34777 
34778  // Do not perform refinement if there are no more than two vertices
34779  // (open curve version)
34780  // New size of the vector
34781  n_vertex = tmp_vector_vertex_node.size();
34782 
34783  //------------------------------------------------
34784  /// Refinement
34785  //------------------------------------------------
34786  double refinement_tolerance =
34787  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34788  if (refinement_tolerance > 0.0 && n_vertex >= 2)
34789  {
34790  refinement_was_performed = refine_boundary(face_mesh_pt[p],
34791  tmp_vector_vertex_node,
34792  refinement_tolerance,
34793  check_only);
34794 
34795  // In this case the unrefinement_was_performed variable actually
34796  // tell us if the update had been performed when calling
34797  // with check_only=false
34798  if (check_only && refinement_was_performed)
34799  {
34800  // Cleanup (but only the elements -- the nodes still exist in
34801  // the bulk mesh!
34802  for (unsigned p = 0; p < n_polyline; p++)
34803  {
34804  face_mesh_pt[p]->flush_node_storage();
34805  delete face_mesh_pt[p];
34806  }
34807  return true;
34808  }
34809 
34810  } // end refinement
34811 
34812  // Do not perform maximum length constraint if there are no more than
34813  // two vertices
34814  // New size of the vector
34815  n_vertex = tmp_vector_vertex_node.size();
34816 
34817  //------------------------------------------------
34818  // Maximum length constraint
34819  //-----------------------------------------------
34820  double maximum_length =
34821  open_polyline_pt->polyline_pt(p)->maximum_length();
34822  if (maximum_length > 0.0 && n_vertex >= 2)
34823  {
34824  bool max_length_applied = false;
34825  max_length_applied = apply_max_length_constraint(
34826  face_mesh_pt[p], tmp_vector_vertex_node, maximum_length);
34827 
34828  // In this case the max length criteria was applied, check if
34829  // check_only=false
34830  if (check_only && max_length_applied)
34831  {
34832  // Cleanup (but only the elements -- the nodes still exist in
34833  // the bulk mesh!
34834  for (unsigned p = 0; p < n_polyline; p++)
34835  {
34836  face_mesh_pt[p]->flush_node_storage();
34837  delete face_mesh_pt[p];
34838  }
34839  return true;
34840  }
34841  }
34842 
34843  // For further processing the three-dimensional vector
34844  // has to be reduced to a two-dimensional vector
34845  n_vertex = tmp_vector_vertex_node.size();
34846  Vector<Vector<double>> vector_vertex_node(n_vertex);
34847 
34848  for (unsigned i = 0; i < n_vertex; i++)
34849  {
34850  vector_vertex_node[i].resize(2);
34851  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
34852  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
34853  }
34854 
34855 #ifdef OOMPH_HAS_MPI
34856  // Only perform this checking if the mesh is not distributed. When
34857  // the mesh is distributed the polylines continuity is addressed
34858  // in the sort_polylines_helper() method
34859  if (!this->is_mesh_distributed())
34860 #endif
34861  {
34862  // Check whether the segments are continguous (first vertex of this
34863  // segment is equal to last vertex of previous segment).
34864  // If not, we should reverse the order of the current segment.
34865  // This check only applies for segments other than the first.
34866  // We only bother with this check, if we actually perform an update
34867  // of the polyline, i.e. if it's not only a check
34868  if ((p > 0) && !check_only)
34869  {
34870  // Final end point of previous line
34871  Vector<double> final_vertex_of_previous_segment;
34872  open_polyline_pt->polyline_pt(p - 1)->final_vertex_coordinate(
34873  final_vertex_of_previous_segment);
34874 
34875  unsigned prev_seg_boundary_id =
34876  open_polyline_pt->curve_section_pt(p - 1)->boundary_id();
34877 
34878  // Find the error between the final vertex of the previous
34879  // line and the first vertex of the current line
34880  double error = 0.0;
34881  for (unsigned i = 0; i < 2; i++)
34882  {
34883  const double dist = final_vertex_of_previous_segment[i] -
34884  (*vector_vertex_node.begin())[i];
34885  error += dist * dist;
34886  }
34887  error = sqrt(error);
34888 
34889  // If the error is bigger than the tolerance then
34890  // we probably need to reverse, but better check
34891  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34892  {
34893  // Find the error between the final vertex of the previous
34894  // line and the first vertex of the current line
34895  error = 0.0;
34896  for (unsigned i = 0; i < 2; i++)
34897  {
34898  const double dist = final_vertex_of_previous_segment[i] -
34899  (*--vector_vertex_node.end())[i];
34900  error += dist * dist;
34901  }
34902  error = sqrt(error);
34903 
34904  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34905  {
34906  // It could be possible that the first segment be reversed
34907  // and we did not notice it because this check does not
34908  // apply for the first segment. We can verify if the first
34909  // segment is reversed by using the vertex number 1
34910  if (p == 1)
34911  {
34912  // If no found it is possible that the previous polyline
34913  // be reversed Check for that case Initial point of
34914  // previous line
34915  Vector<double> initial_vertex_of_previous_segment;
34916  open_polyline_pt->polyline_pt(p - 1)->initial_vertex_coordinate(
34917  initial_vertex_of_previous_segment);
34918 
34919  // Find the error between the initial vertex of the previous
34920  // line and the first vertex of the current line
34921  error = 0.0;
34922  for (unsigned i = 0; i < 2; i++)
34923  {
34924  const double dist = initial_vertex_of_previous_segment[i] -
34925  (*vector_vertex_node.begin())[i];
34926  error += dist * dist;
34927  }
34928  error = sqrt(error);
34929 
34930  // If the error is bigger than the tolerance then
34931  // we probably need to reverse, but better check
34932  if (error >
34933  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34934  {
34935  // Find the error between the final vertex of the previous
34936  // line and the first vertex of the current line
34937  error = 0.0;
34938  for (unsigned i = 0; i < 2; i++)
34939  {
34940  const double dist = initial_vertex_of_previous_segment[i] -
34941  (*--vector_vertex_node.end())[i];
34942  error += dist * dist;
34943  }
34944  error = sqrt(error);
34945 
34946  if (error >
34947  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34948  {
34949  std::ostringstream error_stream;
34950  error_stream
34951  << "The distance between the first node of the current\n"
34952  << "line segment (boundary " << bound
34953  << ") and either end of the previous line segment\n"
34954  << "(boundary " << prev_seg_boundary_id
34955  << ") is bigger than "
34956  << "the desired tolerance "
34957  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34958  << ".\n"
34959  << "This suggests that the polylines defining the open "
34960  << "curve\n"
34961  << "representation are not properly ordered.\n"
34962  << "Fail on last vertex of polyline: ("
34963  << prev_seg_boundary_id
34964  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34965  << "This should have failed when first trying to "
34966  "construct\n"
34967  << "the open curve.\n";
34968  throw OomphLibError(error_stream.str(),
34969  OOMPH_CURRENT_FUNCTION,
34970  OOMPH_EXCEPTION_LOCATION);
34971  }
34972  else // We have to reverse both
34973  {
34974  // First reverse the previous polyline
34975  open_polyline_pt->polyline_pt(p - 1)->reverse();
34976  // Then reverse the current polyline
34977  std::reverse(vector_vertex_node.begin(),
34978  vector_vertex_node.end());
34979  }
34980  }
34981  else
34982  {
34983  // Reverse the previous polyline only
34984  open_polyline_pt->polyline_pt(p - 1)->reverse();
34985  }
34986  } // if (p == 1)
34987  else
34988  {
34989  std::ostringstream error_stream;
34990  error_stream
34991  << "The distance between the first node of the current\n"
34992  << "line segment (boundary " << bound
34993  << ") and either end of "
34994  << "the previous line segment\n"
34995  << "(boundary " << prev_seg_boundary_id
34996  << ") is bigger than the "
34997  << "desired tolerance "
34998  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34999  << ".\n"
35000  << "This suggests that the polylines defining the polygonal\n"
35001  << "representation are not properly ordered.\n"
35002  << "Fail on last vertex of polyline: ("
35003  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
35004  << bound << ").\n"
35005  << "This should have failed when first trying to construct "
35006  "the\n"
35007  << "polygon.\n";
35008  throw OomphLibError(error_stream.str(),
35009  OOMPH_CURRENT_FUNCTION,
35010  OOMPH_EXCEPTION_LOCATION);
35011  }
35012  }
35013  else
35014  {
35015  // Reverse the current vector to line up with the previous one
35016  std::reverse(vector_vertex_node.begin(),
35017  vector_vertex_node.end());
35018  }
35019  }
35020 
35021  } // if p > 0
35022 
35023  } // is mesh not distributed?
35024 
35025  if (!check_only)
35026  {
35027  // Now update the polyline according to the new vertices The new
35028  // one representation
35029  TriangleMeshPolyLine* tmp_polyline =
35030  new TriangleMeshPolyLine(vector_vertex_node, bound);
35031 
35032  // Create a temporal "curve section" version of the recently
35033  // created polyline
35034  TriangleMeshCurveSection* tmp_curve_section = tmp_polyline;
35035 
35036  // Copy the unrefinement and refinement information
35037  tmp_polyline->set_unrefinement_tolerance(unrefinement_tolerance);
35038  tmp_polyline->set_refinement_tolerance(refinement_tolerance);
35039 
35040  // Establish the maximum length constraint
35041  tmp_polyline->set_maximum_length(maximum_length);
35042 
35043  // Pass the connection information from the old polyline to the
35044  // new one
35045  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
35046  tmp_curve_section);
35047 
35048  std::set<TriangleMeshCurveSection*>::iterator it =
35049  this->Free_curve_section_pt.find(
35050  open_polyline_pt->curve_section_pt(p));
35051 
35052  bool delete_it_on_destructor = false;
35053 
35054  if (it != this->Free_curve_section_pt.end())
35055  {
35056  // Free previous representation only if you created
35057  this->Free_curve_section_pt.erase(it);
35058  delete open_polyline_pt->curve_section_pt(p);
35059  delete_it_on_destructor = true;
35060  }
35061 
35062  // *****************************************************************
35063  // Copying the new representation
35064  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
35065 
35066  // Update the Boundary <--> PolyLine map
35067  this->Boundary_curve_section_pt[bound] =
35068  open_polyline_pt->curve_section_pt(p);
35069 
35070  if (delete_it_on_destructor)
35071  {
35072  this->Free_curve_section_pt.insert(
35073  open_polyline_pt->curve_section_pt(p));
35074  }
35075 
35076  } // if(!check_only)
35077 
35078  } // n_polylines
35079 
35080  // Cleanup (but only the elements -- the nodes still exist in
35081  // the bulk mesh!
35082  for (unsigned p = 0; p < n_polyline; p++)
35083  {
35084  face_mesh_pt[p]->flush_node_storage();
35085  delete face_mesh_pt[p];
35086  }
35087 
35088  if (check_only)
35089  {
35090  // if we end up all the way down here, no update of the internal
35091  // boundaries is necessary (in case we only check)
35092  return false;
35093  }
35094  else
35095  {
35096  // if we not only check, but actually perform the update and end
35097  // up all the way down here then we indicate whether an update was
35098  // performed or not
35099  return (unrefinement_was_performed || refinement_was_performed ||
35100  max_length_applied);
35101  }
35102  }
35103 
35104  //=========================================================================
35105  /// \short Helper function that performs the unrefinement process
35106  /// on the specified boundary by using the provided vertices
35107  /// representation. Optional boolean is used to run it as test only (if
35108  /// true is specified as input) in which case vertex coordinates aren't
35109  /// actually modified. Returned boolean indicates if polyline was (or
35110  /// would have been -- if called with check_only=false) changed.
35111  //=========================================================================
35112  template<class ELEMENT>
35114  const unsigned& b,
35115  const unsigned& c,
35116  Vector<Vector<double>>& vector_bnd_vertices,
35117  double& unrefinement_tolerance,
35118  const bool& check_only)
35119  {
35120  // Store the vertices not allowed for deletion
35121  std::set<Vector<double>> no_delete_vertex;
35122 
35123  // Does the boundary receives connections?
35124  const bool boundary_receive_connections =
35125  this->boundary_connections(b, c, no_delete_vertex);
35126 
35127  // Boolean that indicates whether an actual update of the vertex
35128  // coordinates was performed or not
35129  bool unrefinement_was_performed = false;
35130 
35131  unsigned n_vertex = vector_bnd_vertices.size();
35132 
35133  // Initialise counter that indicates at which vertex we're currently
35134  // considering for deletion
35135  unsigned counter = 1;
35136 
35137  // Loop over the nodes; start with the second one and increment by two
35138  // this way a "pack" of three nodes will be considered for calculation:
35139  // the middle-node (which is to be deleted or not) and the adjacent
35140  // nodes
35141  for (unsigned i = 1; i <= n_vertex - 2; i += 2)
35142  {
35143  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35144  double a_x = vector_bnd_vertices[i - 1][1];
35145  double a_y = vector_bnd_vertices[i - 1][2];
35146  double b_x = vector_bnd_vertices[i][1];
35147  double b_y = vector_bnd_vertices[i][2];
35148  double c_x = vector_bnd_vertices[i + 1][1];
35149  double c_y = vector_bnd_vertices[i + 1][2];
35150 
35151  double a = b_x - a_x;
35152  double b = b_y - a_y;
35153  double c = c_x - a_x;
35154  double d = c_y - a_y;
35155 
35156  double e = a * (a_x + b_x) + b * (a_y + b_y);
35157  double f = c * (a_x + c_x) + d * (a_y + c_y);
35158 
35159  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
35160 
35161  bool do_it = false;
35162  if (std::fabs(g) < 1.0e-14)
35163  {
35164  do_it = true;
35165  if (check_only)
35166  {
35167  return true;
35168  }
35169  }
35170  else
35171  {
35172  double p_x = (d * e - b * f) / g;
35173  double p_y = (a * f - c * e) / g;
35174 
35175  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
35176 
35177  double rhalfca_x = 0.5 * (a_x - c_x);
35178  double rhalfca_y = 0.5 * (a_y - c_y);
35179 
35180  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
35181 
35182  double sticky_out_bit = r - sqrt(std::fabs((r * r) - halfca_squared));
35183 
35184  // If sticky out bit divided by distance between end nodes
35185  // is less than tolerance the boundary is so flat that we
35186  // can safely kill the node
35187  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
35188  unrefinement_tolerance)
35189  {
35190  do_it = true;
35191  if (check_only)
35192  {
35193  return true;
35194  }
35195  }
35196  }
35197 
35198  // If the vertex was proposed for deletion check that it is
35199  // allowed for being deleted
35200  if (do_it && boundary_receive_connections)
35201  {
35202  // Is the vertex one of the non deletable vertices
35203  for (std::set<Vector<double>>::iterator it = no_delete_vertex.begin();
35204  it != no_delete_vertex.end();
35205  it++)
35206  {
35207  // Compute the distance between the proposed node to delete
35208  // and the ones that should not be deleted
35209  const double x = (*it)[0];
35210  const double y = (*it)[1];
35211  double error = (b_x - x) * (b_x - x) + (b_y - y) * (b_y - y);
35212  error = sqrt(error);
35213 
35214  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35215  {
35216  // Do not delete the vertex
35217  do_it = false;
35218  break;
35219  }
35220  }
35221 
35222  } // if (do_it && boundary_receive_connections)
35223 
35224  // Remove node?
35225  if (do_it)
35226  {
35227  vector_bnd_vertices[i].resize(0);
35228  }
35229 
35230  // Increase the counter, that indicates the number of the
35231  // next middle node
35232  counter += 2;
35233  }
35234 
35235  // coming out of here the value of counter is the index of the
35236  // last node on the polyline counter=n_vertex-1 (in case of an
35237  // even number of nodes) or counter has the value of the number
35238  // of nodes on the polyline counter=n_vertex (in case of an odd
35239  // number of nodes
35240 
35241  // Special treatment for the end of the polyline:
35242  // If the number of nodes is even, then the previous loop stopped
35243  // at the last but second node, i.e. the current value of counter
35244  // is the index of the last node. If that's the case, the last but
35245  // one node needs to be treated separately
35246  if ((counter) == (n_vertex - 1))
35247  {
35248  // Set the last but one node as middle node
35249  unsigned i = vector_bnd_vertices.size() - 2;
35250 
35251  // Index of the current! last but second node (considering any
35252  // previous deletion)
35253  unsigned n = 0;
35254 
35255  if (vector_bnd_vertices[counter - 2].size() != 0)
35256  {
35257  // if the initial last but second node does still exist then
35258  // this one is obviously also the current last but second one
35259  n = counter - 2;
35260  }
35261  else
35262  {
35263  // if the initial last but second node was deleted then the
35264  // initial last but third node is the current last but second
35265  // node
35266  n = counter - 3;
35267  }
35268 
35269  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
35270  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
35271  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
35272 
35273  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35274  double a_x = vector_bnd_vertices[n][1];
35275  double a_y = vector_bnd_vertices[n][2];
35276  double b_x = vector_bnd_vertices[i][1];
35277  double b_y = vector_bnd_vertices[i][2];
35278  double c_x = vector_bnd_vertices[i + 1][1];
35279  double c_y = vector_bnd_vertices[i + 1][2];
35280 
35281  double a = b_x - a_x;
35282  double b = b_y - a_y;
35283  double c = c_x - a_x;
35284  double d = c_y - a_y;
35285 
35286  double e = a * (a_x + b_x) + b * (a_y + b_y);
35287  double f = c * (a_x + c_x) + d * (a_y + c_y);
35288 
35289  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
35290 
35291  bool do_it = false;
35292  if (std::fabs(g) < 1.0e-14)
35293  {
35294  do_it = true;
35295  if (check_only)
35296  {
35297  return true;
35298  }
35299  }
35300  else
35301  {
35302  double p_x = (d * e - b * f) / g;
35303  double p_y = (a * f - c * e) / g;
35304 
35305  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
35306 
35307  double rhalfca_x = 0.5 * (a_x - c_x);
35308  double rhalfca_y = 0.5 * (a_y - c_y);
35309 
35310  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
35311 
35312  double sticky_out_bit = r - sqrt(std::fabs((r * r) - halfca_squared));
35313 
35314  // If sticky out bit divided by distance between end nodes
35315  // is less than tolerance the boundary is so flat that we
35316  // can safely kill the node
35317  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
35318  unrefinement_tolerance)
35319  {
35320  do_it = true;
35321  if (check_only)
35322  {
35323  return true;
35324  }
35325  }
35326  }
35327 
35328  // If the vertex was proposed for deletion check that it is
35329  // allowed for being deleted
35330  if (do_it && boundary_receive_connections)
35331  {
35332  // Is the vertex one of the non deletable vertices
35333  for (std::set<Vector<double>>::iterator it = no_delete_vertex.begin();
35334  it != no_delete_vertex.end();
35335  it++)
35336  {
35337  // Compute the distance between the proposed node to delete
35338  // and the ones that should not be deleted
35339  const double x = (*it)[0];
35340  const double y = (*it)[1];
35341  double error = (b_x - x) * (b_x - x) + (b_y - y) * (b_y - y);
35342  error = sqrt(error);
35343 
35344  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35345  {
35346  // Do not delete the vertex
35347  do_it = false;
35348  break;
35349  }
35350  }
35351 
35352  } // if (do_it && boundary_receive_connections)
35353 
35354  // Remove node?
35355  if (do_it)
35356  {
35357  vector_bnd_vertices[i].resize(0);
35358  }
35359  }
35360 
35361  // Create another vector, which will only contain entries of
35362  // nodes that still exist
35363  Vector<Vector<double>> compact_vector;
35364  compact_vector.reserve(n_vertex);
35365  for (unsigned i = 0; i < n_vertex; i++)
35366  {
35367  // If the entry was not deleted include it in the new vector
35368  if (vector_bnd_vertices[i].size() != 0)
35369  {
35370  compact_vector.push_back(vector_bnd_vertices[i]);
35371  }
35372  }
35373 
35374  /// Get the size of the vector that now includes all remaining nodes
35375  n_vertex = compact_vector.size();
35376 
35377  // If the size of the vector containing the remaining nodes is
35378  // different from the size of the vector before the unrefinement
35379  // routine (with the original nodes)
35380  // then the polyline was obviously updated
35381  if (n_vertex != vector_bnd_vertices.size())
35382  {
35383  unrefinement_was_performed = true;
35384  }
35385 
35386  /// Copy back
35387  vector_bnd_vertices.resize(n_vertex);
35388  for (unsigned i = 0; i < n_vertex; i++)
35389  {
35390  vector_bnd_vertices[i].resize(3);
35391  vector_bnd_vertices[i][0] = compact_vector[i][0];
35392  vector_bnd_vertices[i][1] = compact_vector[i][1];
35393  vector_bnd_vertices[i][2] = compact_vector[i][2];
35394  }
35395 
35396  return unrefinement_was_performed;
35397  }
35398 
35399  //=========================================================================
35400  /// \short Helper function that performs the refinement process
35401  /// on the specified boundary by using the provided vertices
35402  /// representation. Optional boolean is used to run it as test only (if
35403  /// true is specified as input) in which case vertex coordinates aren't
35404  /// actually modified. Returned boolean indicates if polyline was (or
35405  /// would have been -- if called with check_only=false) changed.
35406  //=========================================================================
35407  template<class ELEMENT>
35409  Mesh* face_mesh_pt,
35410  Vector<Vector<double>>& vector_bnd_vertices,
35411  double& refinement_tolerance,
35412  const bool& check_only)
35413  {
35414  // Boolean that indicates whether an actual update of the vertex
35415  // coordinates was performed or not
35416  bool refinement_was_performed = false;
35417 
35418  // Create a geometric object from the mesh to represent
35419  // the curvilinear boundary
35420  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
35421 
35422  // Get the total number of current vertices
35423  unsigned n_vertex = vector_bnd_vertices.size();
35424 
35425  // Create a new (temporary) vector for the nodes, so
35426  // that new nodes can be stored
35427  Vector<Vector<double>> extended_vector;
35428 
35429  // Reserve memory space for twice the number of already
35430  // existing nodes (worst case)
35431  extended_vector.reserve(2 * n_vertex);
35432 
35433  // Loop over the nodes until the last but one node
35434  for (unsigned inod = 0; inod < n_vertex - 1; inod++)
35435  {
35436  // Get local coordinate of "left" node
35437  double zeta_left = vector_bnd_vertices[inod][0];
35438 
35439  // Get position vector of "left" node
35440  Vector<double> R_left(2);
35441  for (unsigned i = 0; i < 2; i++)
35442  {
35443  R_left[i] = vector_bnd_vertices[inod][i + 1];
35444  }
35445 
35446  // Get local coordinate of "right" node
35447  double zeta_right = vector_bnd_vertices[inod + 1][0];
35448 
35449  // Get position vector of "right" node
35450  Vector<double> R_right(2);
35451  for (unsigned i = 0; i < 2; i++)
35452  {
35453  R_right[i] = vector_bnd_vertices[inod + 1][i + 1];
35454  }
35455 
35456  // Get the boundary coordinate of the midpoint
35457  Vector<double> zeta_mid(1);
35458  zeta_mid[0] = 0.5 * (zeta_left + zeta_right);
35459 
35460  // Get the position vector of the midpoint on the
35461  // curvilinear boundary
35462  Vector<double> R_mid(2);
35463  mesh_geom_obj_pt->position(zeta_mid, R_mid);
35464 
35465  // Get the position vector of the midpoint on the straight
35466  // line connecting "left" and "right" node
35467  Vector<double> R_mid_polygon(2);
35468  for (unsigned i = 0; i < 2; i++)
35469  {
35470  R_mid_polygon[i] = 0.5 * (R_right[i] + R_left[i]);
35471  }
35472 
35473  // Calculate the distance between the midpoint on the curvilinear
35474  // boundary and the midpoint on the straight line
35475  double distance =
35476  sqrt((R_mid[0] - R_mid_polygon[0]) * (R_mid[0] - R_mid_polygon[0]) +
35477  (R_mid[1] - R_mid_polygon[1]) * (R_mid[1] - R_mid_polygon[1]));
35478 
35479  // Calculating the length of the straight line
35480  double length = sqrt((R_right[0] - R_left[0]) * (R_right[0] - R_left[0]) +
35481  (R_right[1] - R_left[1]) * (R_right[1] - R_left[1]));
35482 
35483  // If the ratio of distance between the midpoints to the length
35484  // of the straight line is larger than the tolerance
35485  // specified for the criterion when points can be deleted,
35486  // create a new node and add it to the (temporary) vector
35487  if ((distance / length) > refinement_tolerance)
35488  {
35489  if (check_only)
35490  {
35491  // Delete the allocated memory for the geometric object
35492  // that represents the curvilinear boundary
35493  delete mesh_geom_obj_pt;
35494  return true;
35495  }
35496 
35497  Vector<double> new_node(3);
35498  new_node[0] = zeta_mid[0];
35499  new_node[1] = R_mid[0];
35500  new_node[2] = R_mid[1];
35501 
35502  // Include the "left" node in the new "temporary" vector
35503  extended_vector.push_back(vector_bnd_vertices[inod]);
35504 
35505  // Include the new node as well
35506  extended_vector.push_back(new_node);
35507  }
35508  else
35509  {
35510  // Include the "left" node in the new "temporary" vector
35511  // and move on to the next node
35512  extended_vector.push_back(vector_bnd_vertices[inod]);
35513  }
35514  } // end of loop over nodes
35515 
35516  // Add the last node to the vector
35517  extended_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
35518 
35519  /// Get the size of the vector that now includes all added nodes
35520  n_vertex = extended_vector.size();
35521 
35522  // If the size of the vector including the added nodes is
35523  // different from the size of the vector before the refinement
35524  // routine then the polyline was obviously updated
35525  if (n_vertex != vector_bnd_vertices.size())
35526  {
35527  refinement_was_performed = true;
35528  }
35529 
35530  // Copy across
35531  vector_bnd_vertices.resize(n_vertex);
35532  for (unsigned i = 0; i < n_vertex; i++)
35533  {
35534  vector_bnd_vertices[i].resize(3);
35535  vector_bnd_vertices[i][0] = extended_vector[i][0];
35536  vector_bnd_vertices[i][1] = extended_vector[i][1];
35537  vector_bnd_vertices[i][2] = extended_vector[i][2];
35538  }
35539 
35540  // Delete the allocated memory for the geometric object
35541  // that represents the curvilinear boundary
35542  delete mesh_geom_obj_pt;
35543 
35544  return refinement_was_performed;
35545  }
35546 
35547  //=========================================================================
35548  // \short Helper function that applies the maximum length constraint
35549  // when it was specified. This will increase the number of points in
35550  // the current curve section in case that any segment on it does not
35551  // fulfils the requirement
35552  //=========================================================================
35553  template<class ELEMENT>
35555  Mesh* face_mesh_pt,
35556  Vector<Vector<double>>& vector_bnd_vertices,
35557  double& max_length_constraint)
35558  {
35559  // Boolean that indicates whether an actual update of the vertex
35560  // coordinates was performed or not
35561  bool max_length_applied = false;
35562 
35563  // Create a geometric object from the mesh to represent
35564  // the curvilinear boundary
35565  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
35566 
35567  // Get the total number of current vertices
35568  unsigned n_vertex = vector_bnd_vertices.size();
35569 
35570  // Create a new (temporary) vector for the nodes, so
35571  // that new nodes can be stored
35572  Vector<Vector<double>> extended_vector;
35573 
35574  // Loop over the nodes until the last but one node
35575  for (unsigned inod = 0; inod < n_vertex - 1; inod++)
35576  {
35577  // Get local coordinate of "left" node
35578  double zeta_left = vector_bnd_vertices[inod][0];
35579 
35580  // Get position vector of "left" node
35581  Vector<double> R_left(2);
35582  for (unsigned i = 0; i < 2; i++)
35583  {
35584  R_left[i] = vector_bnd_vertices[inod][i + 1];
35585  }
35586 
35587  // Get local coordinate of "right" node
35588  double zeta_right = vector_bnd_vertices[inod + 1][0];
35589 
35590  // Get position vector of "right" node
35591  Vector<double> R_right(2);
35592  for (unsigned i = 0; i < 2; i++)
35593  {
35594  R_right[i] = vector_bnd_vertices[inod + 1][i + 1];
35595  }
35596 
35597  // Include the "left" node in the new "temporary" vector
35598  extended_vector.push_back(vector_bnd_vertices[inod]);
35599 
35600  // Check whether the current distance between the left and right node
35601  // is longer than the specified constraint or not
35602  double length = std::fabs(zeta_right - zeta_left);
35603 
35604  // Do we need to introduce new nodes?
35605  if (length > max_length_constraint)
35606  {
35607  double n_pts = length / max_length_constraint;
35608  // We only want the integer part
35609  unsigned n_points = static_cast<unsigned>(n_pts);
35610  double zeta_increment =
35611  (zeta_right - zeta_left) / ((double)n_points + 1);
35612 
35613  Vector<double> zeta(1);
35614  // Create the n_points+1 points inside the segment
35615  for (unsigned s = 1; s < n_points + 1; s++)
35616  {
35617  // Get the coordinates
35618  zeta[0] = zeta_left + zeta_increment * double(s);
35619  Vector<double> vertex(2);
35620  mesh_geom_obj_pt->position(zeta, vertex);
35621 
35622  // Create the new node
35623  Vector<double> new_node(3);
35624  new_node[0] = zeta[0];
35625  new_node[1] = vertex[0];
35626  new_node[2] = vertex[1];
35627 
35628  // Include the new node
35629  extended_vector.push_back(new_node);
35630  }
35631  }
35632  }
35633 
35634  // Add the last node to the vector
35635  extended_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
35636 
35637  /// Get the size of the vector that now includes all added nodes
35638  n_vertex = extended_vector.size();
35639 
35640  // If the size of the vector including the added nodes is
35641  // different from the size of the vector before applying the maximum length
35642  // constraint then the polyline was obviously updated
35643  if (n_vertex != vector_bnd_vertices.size())
35644  {
35645  max_length_applied = true;
35646  }
35647 
35648  // Copy across
35649  vector_bnd_vertices.resize(n_vertex);
35650  for (unsigned i = 0; i < n_vertex; i++)
35651  {
35652  vector_bnd_vertices[i].resize(3);
35653  vector_bnd_vertices[i][0] = extended_vector[i][0];
35654  vector_bnd_vertices[i][1] = extended_vector[i][1];
35655  vector_bnd_vertices[i][2] = extended_vector[i][2];
35656  }
35657 
35658  // Delete the allocated memory for the geometric object
35659  // that represents the curvilinear boundary
35660  delete mesh_geom_obj_pt;
35661 
35662  return max_length_applied;
35663  }
35664 
35665  //=========================================================================
35666  /// \short Helper function
35667  /// Creates an unsorted face mesh representation from the specified
35668  /// boundary id. It means that the elements are not sorted along the
35669  /// boundary
35670  //=========================================================================
35671  template<class ELEMENT>
35673  create_unsorted_face_mesh_representation(const unsigned& boundary_id,
35674  Mesh* face_mesh_pt)
35675  {
35676  // Create a face mesh adjacent to specified boundary.
35677  // The face mesh consists of FaceElements that may also be
35678  // interpreted as GeomObjects
35679 
35680  // Build the face mesh
35681  this->template build_face_mesh<ELEMENT, FaceElementAsGeomObject>(
35682  boundary_id, face_mesh_pt);
35683 
35684  // Find the total number of added elements
35685  unsigned n_element = face_mesh_pt->nelement();
35686  // Loop over the elements
35687  for (unsigned e = 0; e < n_element; e++)
35688  {
35689  // Cast the element pointer to the correct thing!
35690  FaceElementAsGeomObject<ELEMENT>* el_pt =
35691  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>(
35692  face_mesh_pt->element_pt(e));
35693 
35694  // Set bulk boundary number
35695  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35696  }
35697  }
35698 
35699  //=========================================================================
35700  /// \short Helper function
35701  /// Creates a sorted face mesh representation of the specified PolyLine
35702  /// It means that the elements are sorted along the boundary
35703  //=========================================================================
35704  template<class ELEMENT>
35706  const unsigned& boundary_id,
35707  Mesh* face_mesh_pt,
35708  std::map<FiniteElement*, bool>& is_inverted,
35709  bool& inverted_face_mesh)
35710  {
35711  Mesh* tmp_unsorted_face_mesh_pt = new Mesh();
35712 
35713  // First step we get the unsorted version of the face mesh
35714  create_unsorted_face_mesh_representation(boundary_id,
35715  tmp_unsorted_face_mesh_pt);
35716 
35717  // Once with the unsorted version of the face mesh
35718  // only left to sort it out!!!
35719 
35720  // Put all face elements in order
35721  //-------------------------------
35722 
35723  // Put first element into ordered list
35724  // Temporal list for sorting the elements
35725  std::list<FiniteElement*> sorted_el_pt;
35726  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35727  sorted_el_pt.push_back(el_pt);
35728 
35729  // Number of nodes
35730  unsigned nnod = el_pt->nnode();
35731 
35732  // Count elements that have been done
35733  unsigned count_done = 0;
35734 
35735  // How many face elements are there?
35736  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35737 
35738  // Keep track of who's done
35739  std::map<FiniteElement*, bool> done_el;
35740 
35741  is_inverted.clear();
35742 
35743  // Fit in the other elements in at most nel^2 loops
35744  for (unsigned ee = 1; ee < n_face_element; ee++)
35745  {
35746  // Loop over all elements to check if they fit to the right
35747  // or the left of the current one
35748  for (unsigned e = 1; e < n_face_element; e++)
35749  {
35750  // Candidate element
35751  el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35752 
35753  // Is it done yet?
35754  if (!done_el[el_pt])
35755  {
35756  // Left and rightmost elements
35757  FiniteElement* first_el_pt = (*sorted_el_pt.begin());
35758  std::list<FiniteElement*>::iterator it = sorted_el_pt.end();
35759  it--;
35760  FiniteElement* last_el_pt = *it;
35761 
35762  // Left and rightmost nodes
35763  Node* left_node_pt = first_el_pt->node_pt(0);
35764  if (is_inverted[first_el_pt])
35765  {
35766  left_node_pt = first_el_pt->node_pt(nnod - 1);
35767  }
35768  Node* right_node_pt = last_el_pt->node_pt(nnod - 1);
35769  if (is_inverted[last_el_pt])
35770  {
35771  right_node_pt = last_el_pt->node_pt(0);
35772  }
35773 
35774  // New element fits at the left of first element and is not inverted
35775  if (left_node_pt == el_pt->node_pt(nnod - 1))
35776  {
35777  sorted_el_pt.push_front(el_pt);
35778  done_el[el_pt] = true;
35779  count_done++;
35780  is_inverted[el_pt] = false;
35781  }
35782  // New element fits at the left of first element and is inverted
35783 
35784  else if (left_node_pt == el_pt->node_pt(0))
35785  {
35786  sorted_el_pt.push_front(el_pt);
35787  done_el[el_pt] = true;
35788  count_done++;
35789  is_inverted[el_pt] = true;
35790  }
35791  // New element fits on the right of last element and is not inverted
35792 
35793  else if (right_node_pt == el_pt->node_pt(0))
35794  {
35795  sorted_el_pt.push_back(el_pt);
35796  done_el[el_pt] = true;
35797  count_done++;
35798  is_inverted[el_pt] = false;
35799  }
35800  // New element fits on the right of last element and is inverted
35801 
35802  else if (right_node_pt == el_pt->node_pt(nnod - 1))
35803  {
35804  sorted_el_pt.push_back(el_pt);
35805  done_el[el_pt] = true;
35806  count_done++;
35807  is_inverted[el_pt] = true;
35808  }
35809 
35810  if (done_el[el_pt])
35811  {
35812  break;
35813  }
35814  }
35815  }
35816  }
35817 
35818  // Are we done?
35819  if (count_done != (n_face_element - 1))
35820  {
35821  std::ostringstream error_message;
35822  error_message << "When ordering FaceElements on "
35823  << "boundary " << boundary_id << " only managed to order \n"
35824  << count_done << " of " << n_face_element
35825  << " face elements.\n"
35826  << std::endl;
35827  throw OomphLibError(
35828  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
35829  }
35830 
35831  // Now make a mesh that contains the FaceElements in order
35832  // Remember that we currently have a list, not a mesh of sorted elements
35833 
35834  // Fill it
35835  for (std::list<FiniteElement*>::iterator it = sorted_el_pt.begin();
35836  it != sorted_el_pt.end();
35837  it++)
35838  {
35839  // Get element
35840  FiniteElement* el_pt = *it;
35841 
35842  // add this face element to the order original mesh
35843  face_mesh_pt->add_element_pt(el_pt);
35844  }
35845 
35846  // Verify if face mesh representation is not inverted according to the
35847  // polyline specified by the user, it means that the initial and the
35848  // final vertex does really correspond to the first and last vertex
35849  // respectively, if not, state that the face mesh representation is
35850  // inverted
35851 
35852  // Get the associated polyline representation to the boundary
35853  TriangleMeshPolyLine* bnd_polyline =
35854  this->Boundary_curve_section_pt[boundary_id];
35855 
35856  // Get the really first vertex
35857  Vector<double> first_vertex = bnd_polyline->vertex_coordinate(0);
35858 
35859  // Now get the first node based on the face mesh representation
35860  // First get access to the first element
35861  FiniteElement* first_el_pt = face_mesh_pt->finite_element_pt(0);
35862 
35863  // Now get access to the first node
35864  unsigned n_node = first_el_pt->nnode();
35865  // Get the very first node (taking into account if it is
35866  // inverted or not!!)
35867  Node* first_node_pt = first_el_pt->node_pt(0);
35868  if (is_inverted[first_el_pt])
35869  {
35870  first_node_pt = first_el_pt->node_pt(n_node - 1);
35871  }
35872 
35873  double error = (first_node_pt->x(0) - first_vertex[0]) *
35874  (first_node_pt->x(0) - first_vertex[0]) +
35875  (first_node_pt->x(1) - first_vertex[1]) *
35876  (first_node_pt->x(1) - first_vertex[1]);
35877 
35878  error = sqrt(error);
35879 
35880  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35881  {
35882  inverted_face_mesh = false;
35883  }
35884  else
35885  {
35886  inverted_face_mesh = true;
35887  }
35888  }
35889 
35890  //=========================================================================
35891  /// Helper function to construct face mesh representation of all polylines,
35892  /// possibly with segments re-distributed between polylines
35893  /// to maintain an approximately even sub-division of the polygon
35894  //=========================================================================
35895  template<class ELEMENT>
35897  TriangleMeshPolygon* polygon_pt, Vector<Mesh*>& face_mesh_pt)
35898  {
35899  // Number of polylines
35900  unsigned n_polyline = polygon_pt->npolyline();
35901  face_mesh_pt.resize(n_polyline);
35902 
35903  // Are we eligible for re-distributing polyline segments between
35904  // polylines? We're not if any of the boundaries are associated
35905  // with a GeomObject because we're then tied to the start and
35906  // end coordinates along it.
35907  bool eligible_for_segment_redistribution = true;
35908 
35909  // Loop over constituent polylines
35910  for (unsigned p = 0; p < n_polyline; p++)
35911  {
35912  // Get the boundary id of the polyline
35913  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
35914 
35915  // If the boundary has a geometric object representation then
35916  // we can't redistribute
35917  GeomObject* const geom_object_pt = this->boundary_geom_object_pt(bound);
35918  if (geom_object_pt != 0)
35919  {
35920  eligible_for_segment_redistribution = false;
35921  }
35922 
35923  face_mesh_pt[p] = new Mesh();
35924  create_unsorted_face_mesh_representation(bound, face_mesh_pt[p]);
35925  }
35926 
35927  if (!polygon_pt->is_redistribution_of_segments_between_polylines_enabled())
35928  {
35929  return;
35930  }
35931 
35932  // If there is more than one region we have to think... Die for now.
35933  if (this->nregion() > 1)
35934  {
35935  std::ostringstream warn_message;
35936  warn_message
35937  << "Can't currently re-distribute segments between polylines if there\n"
35938  << "are multiple regions; returning..." << std::endl;
35939  OomphLibWarning(warn_message.str(),
35940  "RefineableTriangleMesh::get_face_mesh_representation()",
35941  OOMPH_EXCEPTION_LOCATION);
35942  return;
35943  }
35944 
35945  // Redistribution overruled
35946  if (!eligible_for_segment_redistribution)
35947  {
35948  std::ostringstream warn_message;
35949  warn_message
35950  << "Over-ruling re-distribution of segments between polylines\n"
35951  << "because at least one boundary is associated with a GeomObject."
35952  << "Returning..." << std::endl;
35953  OomphLibWarning(warn_message.str(),
35954  "RefineableTriangleMesh::get_face_mesh_representation()",
35955  OOMPH_EXCEPTION_LOCATION);
35956  return;
35957  }
35958 
35959  // Create a vector for ordered face mesh
35960  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35961 
35962  // Storage for the total arclength of polygon
35963  double s_total = 0.0;
35964 
35965  // Storage for first and last nodes on polylines so we can figure
35966  // out if they are inverted relative to each other
35967  Vector<Node*> first_polyline_node_pt(n_polyline);
35968  Vector<Node*> last_polyline_node_pt(n_polyline);
35969  std::vector<bool> is_reversed(n_polyline, false);
35970 
35971  // Loop over constituent polylines
35972  for (unsigned p = 0; p < n_polyline; p++)
35973  {
35974  // Put all face elements in order
35975  //-------------------------------
35976 
35977  // Put first element into ordered list
35978  std::list<FiniteElement*> ordered_el_pt;
35979  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(0);
35980  ordered_el_pt.push_back(el_pt);
35981 
35982  // Number of nodes
35983  unsigned nnod = el_pt->nnode();
35984 
35985  // Default for first and last node on polyline
35986  first_polyline_node_pt[p] = el_pt->node_pt(0);
35987  last_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
35988 
35989  // Count elements that have been done
35990  unsigned count_done = 0;
35991 
35992  // How many face elements are there?
35993  unsigned n_face_element = face_mesh_pt[p]->nelement();
35994 
35995  // Get the boundary id of the polyline
35996  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
35997 
35998  // Keep track of who's done
35999  std::map<FiniteElement*, bool> done_el;
36000 
36001  // Keep track of which element is inverted
36002  std::map<FiniteElement*, bool> is_inverted;
36003 
36004  // Fit in the other elements in at most nel^2 loops
36005  for (unsigned ee = 1; ee < n_face_element; ee++)
36006  {
36007  // Loop over all elements to check if they fit to the right
36008  // or the left of the current one
36009  for (unsigned e = 1; e < n_face_element; e++)
36010  {
36011  // Candidate element
36012  el_pt = face_mesh_pt[p]->finite_element_pt(e);
36013 
36014  // Is it done yet?
36015  if (!done_el[el_pt])
36016  {
36017  // Left and rightmost elements
36018  FiniteElement* first_el_pt = (*ordered_el_pt.begin());
36019  std::list<FiniteElement*>::iterator it = ordered_el_pt.end();
36020  it--;
36021  FiniteElement* last_el_pt = *it;
36022 
36023  // Left and rightmost nodes
36024  Node* left_node_pt = first_el_pt->node_pt(0);
36025  if (is_inverted[first_el_pt])
36026  {
36027  left_node_pt = first_el_pt->node_pt(nnod - 1);
36028  }
36029  Node* right_node_pt = last_el_pt->node_pt(nnod - 1);
36030  if (is_inverted[last_el_pt])
36031  {
36032  right_node_pt = last_el_pt->node_pt(0);
36033  }
36034 
36035  // New element fits at the left of first element and is not inverted
36036  if (left_node_pt == el_pt->node_pt(nnod - 1))
36037  {
36038  ordered_el_pt.push_front(el_pt);
36039  done_el[el_pt] = true;
36040  count_done++;
36041  is_inverted[el_pt] = false;
36042  first_polyline_node_pt[p] = el_pt->node_pt(0);
36043  }
36044  // New element fits at the left of first element and is inverted
36045 
36046  else if (left_node_pt == el_pt->node_pt(0))
36047  {
36048  ordered_el_pt.push_front(el_pt);
36049  done_el[el_pt] = true;
36050  count_done++;
36051  is_inverted[el_pt] = true;
36052  first_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
36053  }
36054  // New element fits on the right of last element and is not inverted
36055 
36056  else if (right_node_pt == el_pt->node_pt(0))
36057  {
36058  ordered_el_pt.push_back(el_pt);
36059  done_el[el_pt] = true;
36060  count_done++;
36061  is_inverted[el_pt] = false;
36062  last_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
36063  }
36064  // New element fits on the right of last element and is inverted
36065 
36066  else if (right_node_pt == el_pt->node_pt(nnod - 1))
36067  {
36068  ordered_el_pt.push_back(el_pt);
36069  done_el[el_pt] = true;
36070  count_done++;
36071  is_inverted[el_pt] = true;
36072  last_polyline_node_pt[p] = el_pt->node_pt(0);
36073  }
36074 
36075  if (done_el[el_pt])
36076  {
36077  break;
36078  }
36079  }
36080  }
36081  }
36082 
36083  // Are we done?
36084  if (count_done != (n_face_element - 1))
36085  {
36086  std::ostringstream error_message;
36087  error_message << "When ordering FaceElements on "
36088  << "boundary " << bound << " only managed to order \n"
36089  << count_done << " of " << n_face_element
36090  << " face elements.\n"
36091  << std::endl;
36092  throw OomphLibError(error_message.str(),
36093  OOMPH_CURRENT_FUNCTION,
36094  OOMPH_EXCEPTION_LOCATION);
36095  }
36096 
36097  // Now make a mesh that contains the FaceElements in order
36098  ordered_face_mesh_pt[p] = new Mesh;
36099 
36100  // Fill it
36101  for (std::list<FiniteElement*>::iterator it = ordered_el_pt.begin();
36102  it != ordered_el_pt.end();
36103  it++)
36104  {
36105  // Get element
36106  FiniteElement* el_pt = *it;
36107 
36108  // add this face element to the order original mesh
36109  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
36110  }
36111 
36112  // Get the arclength along the polygon
36113  for (unsigned e = 0; e < n_face_element; ++e)
36114  {
36115  FiniteElement* el_pt = ordered_face_mesh_pt[p]->finite_element_pt(e);
36116  unsigned n_node = el_pt->nnode();
36117  double element_length_squared = 0.0;
36118  for (unsigned i = 0; i < 2; i++)
36119  {
36120  element_length_squared +=
36121  pow(el_pt->node_pt(n_node - 1)->x(i) - el_pt->node_pt(0)->x(i), 2);
36122  }
36123 
36124  // Determine element length
36125  double element_length = sqrt(element_length_squared);
36126 
36127  // Add this length to the total arclength
36128  s_total += element_length;
36129  }
36130 
36131  // Empty the original meshes
36132  face_mesh_pt[p]->flush_element_and_node_storage();
36133  }
36134 
36135  // Is first one reversed?
36136  if ((last_polyline_node_pt[0] == first_polyline_node_pt[1]) ||
36137  (last_polyline_node_pt[0] == last_polyline_node_pt[1]))
36138  {
36139  is_reversed[0] = false;
36140  }
36141  else if ((first_polyline_node_pt[0] == first_polyline_node_pt[1]) ||
36142  (first_polyline_node_pt[0] == last_polyline_node_pt[1]))
36143  {
36144  is_reversed[0] = true;
36145  }
36146 
36147  // Reorder the face meshes so that they are contiguous
36148  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
36149  std::vector<bool> mesh_done(n_polyline, false);
36150  Vector<unsigned> old_polyline_number(n_polyline);
36151 
36152  // Initial entry
36153  tmp_face_mesh_pt[0] = ordered_face_mesh_pt[0];
36154  unsigned current = 0;
36155  old_polyline_number[0] = 0;
36156  unsigned count_found = 0;
36157 
36158  // Fill in the next entries
36159  for (unsigned p = 1; p < n_polyline; p++)
36160  {
36161  Node* end_node_pt = last_polyline_node_pt[current];
36162  if (is_reversed[current])
36163  {
36164  end_node_pt = first_polyline_node_pt[current];
36165  }
36166 
36167  // Loop over all remaining face meshes to see which one fits
36168  for (unsigned pp = 1; pp < n_polyline; pp++)
36169  {
36170  if (!mesh_done[pp])
36171  {
36172  // Current one is not reversed, candidate is not reversed
36173  if ((!is_reversed[current]) &&
36174  (end_node_pt == first_polyline_node_pt[pp]))
36175  {
36176  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36177  mesh_done[pp] = true;
36178  is_reversed[pp] = false;
36179  old_polyline_number[p] = pp;
36180  current = pp;
36181  count_found++;
36182  break;
36183  }
36184  // Current one is not reversed, candidate is reversed
36185 
36186  else if ((!is_reversed[current]) &&
36187  (end_node_pt == last_polyline_node_pt[pp]))
36188  {
36189  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36190  mesh_done[pp] = true;
36191  is_reversed[pp] = true;
36192  old_polyline_number[p] = pp;
36193  current = pp;
36194  count_found++;
36195  break;
36196  }
36197  // Current one is reversed, candidate is not reversed
36198 
36199  else if ((is_reversed[current]) &&
36200  (end_node_pt == first_polyline_node_pt[pp]))
36201  {
36202  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36203  mesh_done[pp] = true;
36204  is_reversed[pp] = false;
36205  old_polyline_number[p] = pp;
36206  current = pp;
36207  count_found++;
36208  break;
36209  }
36210  // Current one is reversed, candidate is reversed
36211 
36212  else if ((is_reversed[current]) &&
36213  (end_node_pt == last_polyline_node_pt[pp]))
36214  {
36215  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36216  mesh_done[pp] = true;
36217  is_reversed[pp] = true;
36218  old_polyline_number[p] = pp;
36219  current = pp;
36220  count_found++;
36221  break;
36222  }
36223  }
36224  }
36225  }
36226 
36227 #ifdef PARANOID
36228  if (count_found != n_polyline - 1)
36229  {
36230  std::ostringstream error_message;
36231  error_message << "Only found " << count_found << " out of "
36232  << n_polyline - 1 << " polylines to be fitted in.\n";
36233  throw OomphLibError(
36234  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36235  }
36236 #endif
36237 
36238  // Now overwrite the re-ordered data
36239  for (unsigned i = 0; i < n_polyline; i++)
36240  {
36241  ordered_face_mesh_pt[i] = tmp_face_mesh_pt[i];
36242  }
36243 
36244  // Now do an approximate equidistribution of polylines
36245  //----------------------------------------------------
36246  double s = 0.0;
36247  unsigned new_face_id = 0;
36248 
36249  // Matrix map to indicate if node must not be removed from specified
36250  // boundary (!=0) or not (=0). Initialises itself to zero
36251  std::map<Node*, std::map<unsigned, unsigned>>
36252  node_must_not_be_removed_from_boundary_flag;
36253 
36254  // Loop over the old face mesh
36255  for (unsigned p = 0; p < n_polyline; p++)
36256  {
36257  // Loop over the face elements
36258  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36259  for (unsigned e = 0; e < n_face_element; e++)
36260  {
36261  unsigned el_number = e;
36262  if (is_reversed[p])
36263  {
36264  el_number = n_face_element - e - 1;
36265  }
36266 
36267  FiniteElement* el_pt =
36268  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36269  unsigned n_node = el_pt->nnode();
36270 
36271  // Determine element length
36272  double element_length_squared = 0.0;
36273  for (unsigned i = 0; i < 2; i++)
36274  {
36275  element_length_squared +=
36276  pow(el_pt->node_pt(n_node - 1)->x(i) - el_pt->node_pt(0)->x(i), 2);
36277  }
36278  double element_length = sqrt(element_length_squared);
36279 
36280  // Add this length to the total arclength
36281  s += element_length;
36282 
36283  // Check if the current 'arclength' is less than the
36284  // whole 'arclength' divided by the number of polylines
36285  if (s < s_total / double(n_polyline) + 1e-6)
36286  {
36287  // If so add this face element to the new face mesh
36288  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36289 
36290  unsigned bound_old =
36291  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36292 
36293  unsigned bound_new =
36294  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36295 
36296  // Loop over the nodes in the element
36297  for (unsigned i = 0; i < n_node; i++)
36298  {
36299  // Get the pointer to the node
36300  Node* nod_pt = el_pt->node_pt(i);
36301 
36302  // If the two boundary id's are different, the face element's nodes
36303  // have to be added to the new boundary
36304  if (bound_new != bound_old)
36305  {
36306  // Add it to the new boundary
36307  add_boundary_node(bound_new, nod_pt);
36308 
36309  // We are happy for this node to be removed from the
36310  // old boundary?
36311  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old] +=
36312  0;
36313  }
36314 
36315  // If the face element hasn't moved, its nodes MUST remain
36316  // on that boundary (incl. any nodes that ar shared by
36317  // FaceElements that have moved (see above)
36318 
36319  else
36320  {
36321  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old] +=
36322  1;
36323  }
36324  }
36325  }
36326 
36327  // If not, reset the current 'arclength' to zero,
36328  // increase the new face id by one and go one element
36329  // back by decreasing e by one to make sure the current
36330  // element gets added to the next face mesh
36331 
36332  else
36333  {
36334  if (new_face_id != n_polyline - 1)
36335  {
36336  s = 0.0;
36337  new_face_id++;
36338  --e;
36339  }
36340  else
36341  {
36342  s = 0.0;
36343  --e;
36344  }
36345  }
36346  }
36347  } // end of loop over all polylines -- they are now re-distributed
36348 
36349 
36350  // Loop over all nodes on the boundaries of the polygon to remove
36351  // nodes from boundaries they are no longer on
36352  unsigned move_count = 0;
36353  for (std::map<Node*, std::map<unsigned, unsigned>>::iterator it =
36354  node_must_not_be_removed_from_boundary_flag.begin();
36355  it != node_must_not_be_removed_from_boundary_flag.end();
36356  it++)
36357  {
36358  // Get the node
36359  Node* nod_pt = (*it).first;
36360 
36361  // Now we loop over the boundaries that this node is on
36362  for (std::map<unsigned, unsigned>::iterator it_2 = (*it).second.begin();
36363  it_2 != (*it).second.end();
36364  it_2++)
36365  {
36366  // Get the boundary id
36367  unsigned bound = (*it_2).first;
36368 
36369  // Remove it from that boundary?
36370  if ((*it_2).second == 0)
36371  {
36372  remove_boundary_node(bound, nod_pt);
36373  move_count++;
36374  }
36375  }
36376  }
36377 
36378  // Loop over the new face mesh to assign new boundary IDs
36379  for (unsigned p = 0; p < n_polyline; p++)
36380  {
36381  // Get the boundary id of the polyline
36382  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
36383 
36384  // Loop over the face elements
36385  unsigned n_face_element = face_mesh_pt[p]->nelement();
36386  for (unsigned e = 0; e < n_face_element; e++)
36387  {
36388  // Cast the element pointer to the correct thing!
36389  FaceElementAsGeomObject<ELEMENT>* el_pt =
36390  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>(
36391  face_mesh_pt[p]->element_pt(e));
36392 
36393  // Set bulk boundary number
36394  el_pt->set_boundary_number_in_bulk_mesh(bound);
36395  }
36396  }
36397 
36398  // Update look-up for elements next to boundary
36399  setup_boundary_element_info();
36400 
36401  // Now re-create the boundary coordinates
36402  for (unsigned p = 0; p < n_polyline; p++)
36403  {
36404  // Get the boundary id of the polyline
36405  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
36406 
36407  // Do it
36408  this->template setup_boundary_coordinates<ELEMENT>(bound);
36409  }
36410 
36411  // Clean up
36412  for (unsigned p = 0; p < n_polyline; p++)
36413  {
36414  // Flush the nodes from the face mesh to make sure we
36415  // don't delete them (the face mesh that we're returning from here
36416  // still needs them!)
36417  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36418  delete ordered_face_mesh_pt[p];
36419  }
36420  }
36421 
36422  //=========================================================================
36423  /// Helper function to construct face mesh representation of all polylines
36424  //=========================================================================
36425  template<class ELEMENT>
36427  TriangleMeshOpenCurve* open_polyline_pt, Vector<Mesh*>& face_mesh_pt)
36428  {
36429  // Number of polylines
36430  unsigned n_polyline = open_polyline_pt->ncurve_section();
36431  face_mesh_pt.resize(n_polyline);
36432 
36433  // Loop over constituent polylines
36434  for (unsigned p = 0; p < n_polyline; p++)
36435  {
36436  // Get the boundary id of the polyline
36437  unsigned bound = open_polyline_pt->curve_section_pt(p)->boundary_id();
36438 
36439  face_mesh_pt[p] = new Mesh();
36440  create_unsorted_face_mesh_representation(bound, face_mesh_pt[p]);
36441  }
36442  }
36443 
36444  //======================================================================
36445  /// Update the PSLG that define the inner boundaries of the mesh.
36446  /// Optional boolean is used to run it as test only (if
36447  /// true is specified as input) in which case PSLG isn't actually
36448  /// modified. Returned boolean indicates if PSLG was (or would have
36449  /// been -- if called with check_only=false) changed.
36450  //======================================================================
36451  template<class ELEMENT>
36453  ELEMENT>::surface_remesh_for_inner_hole_boundaries(Vector<Vector<double>>&
36454  internal_point_coord,
36455  const bool& check_only)
36456  {
36457  // Boolean to indicate whether an actual update of the internal
36458  // holes was performed
36459  bool update_was_performed = false;
36460  // Loop over the number of internal boundaries
36461  unsigned n_hole = internal_point_coord.size();
36462  for (unsigned ihole = 0; ihole < n_hole; ihole++)
36463  {
36464  // Cache the pointer to the polygon representation
36465  TriangleMeshPolygon* const poly_pt = this->Internal_polygon_pt[ihole];
36466 
36467 
36468  // Can the polygon update its own configuration, in which case this
36469  // is easy
36470  if (poly_pt->can_update_reference_configuration())
36471  {
36472  poly_pt->reset_reference_configuration();
36473 
36474  // Initialize Vector hole_coordinates
36475  internal_point_coord[ihole].resize(2);
36476 
36477  // Get the vector of hole coordinates
36478  internal_point_coord[ihole] = poly_pt->internal_point();
36479  }
36480  // Otherwise we have to work much harder
36481 
36482  else
36483  {
36484  // if we only want to check whether an update of the inner
36485  // hole is necessary
36486  if (check_only)
36487  {
36488  // is it necessary?
36489  bool update_necessary =
36490  this->update_polygon_using_face_mesh(poly_pt, check_only);
36491 
36492  // Yes?
36493  if (update_necessary)
36494  {
36495  // then we have to adaptand return 'true'
36496  return true;
36497  }
36498  }
36499  // if we not only want to check, then we actually perform
36500  // the update
36501  else
36502  {
36503  update_was_performed = this->update_polygon_using_face_mesh(poly_pt);
36504  }
36505 
36506  // Now we need to sort out the hole coordinates
36507  if (!poly_pt->internal_point().empty())
36508  {
36509  // If fixed don't update and simply
36510  // Read out the existing value
36511  if (poly_pt->is_internal_point_fixed())
36512  {
36513  // Get the vector of hole coordinates
36514  internal_point_coord[ihole] = poly_pt->internal_point();
36515  }
36516  // This is where the work starts and this could be made much
36517  // better than the current hack
36518  else
36519  {
36520  // If the user has set their own function then use that
36521  if (this->Internal_hole_point_update_fct_pt != 0)
36522  {
36523  this->Internal_hole_point_update_fct_pt(ihole, poly_pt);
36524  }
36525  // Otherwise use our clunky default
36526  else
36527  {
36528  // Now sort out the hole coordinates
36529  Vector<double> vertex_coord;
36530  unsigned n_polyline = poly_pt->npolyline();
36531 
36532  // Initialize Vector hole_coordinates
36533  vertex_coord.resize(2);
36534  internal_point_coord[ihole].resize(2);
36535 
36536  // Hole centre will be found by averaging the position of
36537  // all vertex nodes
36538  internal_point_coord[ihole][0] = 0.0;
36539  internal_point_coord[ihole][1] = 0.0;
36540 
36541  for (unsigned p = 0; p < n_polyline; p++)
36542  {
36543  Vector<double> poly_ave(2, 0.0);
36544  // How many vertices are there in the segment
36545  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36546  for (unsigned v = 0; v < n_vertex; v++)
36547  {
36548  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36549  for (unsigned i = 0; i < 2; i++)
36550  {
36551  poly_ave[i] += vertex_coord[i];
36552  }
36553  }
36554 
36555  // Add the average polyline coordinate to the hole centre
36556  for (unsigned i = 0; i < 2; i++)
36557  {
36558  internal_point_coord[ihole][i] += poly_ave[i] / n_vertex;
36559  }
36560  }
36561 
36562  // Now average out the hole centre
36563  for (unsigned i = 0; i < 2; i++)
36564  {
36565  internal_point_coord[ihole][i] /= n_polyline;
36566  }
36567 
36568  // We have now found the hole centre stored in
36569  // internal_point_coordinate[ihole][i]
36570 
36571  // Find polylines that intersect at y average value
36572  // Alice's version but this does not work if the end point of a
36573  // segment is the intersection point (i.e. at the y average value)
36574  /*Vector<double> vertex_coord2;
36575  unsigned n_intersect=0;
36576  double x_average=0.0;
36577 
36578  for(unsigned p=0;p<n_polyline;p++)
36579  {
36580  //How many vertices are there in the segment
36581  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36582  for(unsigned v=0;v<n_vertex-1;v++)
36583  {
36584  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36585  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36586  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36587  << " " <<
36588  vertex_coord2[0] << " " <<
36589 
36590  vertex_coord2[1] << "\n";
36591  //Does the line between vertices intersect the vertical position
36592  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36593  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36594  {
36595  ++n_intersect; x_average += 0.5*(vertex_coord[0] +
36596  vertex_coord2[0]);
36597  }
36598  }
36599  }
36600 
36601  //Now just report the value if we have had intersections
36602  if(n_intersect != 0)
36603  {
36604  //Report
36605  std::cout << "I have computed a hole " << x_average << " " <<
36606  n_intersect << " "
36607  << x_average/((double)n_intersect) << std::endl;
36608  internal_point_coord[ihole][0] =
36609  x_average/((double)n_intersect);
36610  }
36611  */
36612 
36613  // Set the new hole centre
36614  poly_pt->internal_point() = internal_point_coord[ihole];
36615  // std::cout << "I've had my centre updated to "
36616  // << internal_point_coord[ihole][0]
36617  // << " " << internal_point_coord[ihole][1] << "\n";
36618  }
36619  }
36620  }
36621  }
36622  } // End of the action (n_hole for)
36623 
36624  if (check_only)
36625  {
36626  // If we make it up to here and we only check then no update is required
36627  return false;
36628  }
36629  else
36630  {
36631  // otherwise indicate whether an actual update was performed
36632  return update_was_performed;
36633  }
36634 
36635  } // End of the loop of internal boundaries
36636 
36637  //======================================================================
36638  /// Create the polylines and fill associate data structures, used when
36639  /// creating from a mesh from polyfiles
36640  //======================================================================
36641  template<class ELEMENT>
36643  const std::string& node_file_name, const std::string& poly_file_name)
36644  {
36645  // Get the nodes coordinates (the index of the nodes to build the
36646  // polylines is the one used in the node_file_name file)
36647  // Process node file
36648  // -----------------
36649  std::ifstream node_file(node_file_name.c_str(), std::ios_base::in);
36650 
36651  // Check that the file actually opened correctly
36652  if (!node_file.is_open())
36653  {
36654  std::string error_msg("Failed to open node file: ");
36655  error_msg += "\"" + node_file_name + "\".";
36656  throw OomphLibError(
36657  error_msg, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36658  }
36659 
36660  // Read number of nodes
36661  unsigned nnodes;
36662  node_file >> nnodes;
36663 
36664  // Spatial dimension of nodes
36665  unsigned dimension;
36666  node_file >> dimension;
36667 
36668 #ifdef PARANOID
36669  if (dimension != 2)
36670  {
36671  throw OomphLibError("The dimension must be 2\n",
36672  OOMPH_CURRENT_FUNCTION,
36673  OOMPH_EXCEPTION_LOCATION);
36674  }
36675 #endif
36676 
36677  // Storage the nodes vertices
36678  Vector<double> x_node(nnodes);
36679  Vector<double> y_node(nnodes);
36680 
36681  // Number of attributes
36682  unsigned npoint_attributes;
36683  node_file >> npoint_attributes;
36684  ;
36685 
36686  // Flag for boundary markers
36687  unsigned boundary_markers_flag = 0;
36688  node_file >> boundary_markers_flag;
36689 
36690  // Dummy for node number
36691  unsigned dummy_node_number;
36692  // Dummy for node attribute
36693  unsigned dummy_node_attribute;
36694  // Dummy for node boundary
36695  unsigned dummy_node_boundary;
36696 
36697  // Load in nodal posititions, point attributes
36698  // and boundary markers
36699  for (unsigned i = 0; i < nnodes; i++)
36700  {
36701  node_file >> dummy_node_number;
36702  node_file >> x_node[i];
36703  node_file >> y_node[i];
36704  for (unsigned j = 0; j < npoint_attributes; ++j)
36705  {
36706  node_file >> dummy_node_attribute;
36707  }
36708  if (boundary_markers_flag)
36709  {
36710  node_file >> dummy_node_boundary;
36711  }
36712  }
36713  node_file.close();
36714 
36715  // Get the segments information and use that info. to create the
36716  // polylines
36717 
36718  // A map to store the segments associated to a boundary, non sorted
36719  std::map<unsigned, Vector<std::pair<unsigned, unsigned>>>
36720  unsorted_boundary_segments;
36721 
36722  // Independent storage for the boundaries ids found in the segments so that
36723  // the polylines, and therefore polygons be created in the order they appear
36724  // in the polyfile
36725  Vector<unsigned> sorted_boundaries_ids;
36726 
36727  // Process poly file to extract edges
36728  //-----------------------------------
36729 
36730  // Open poly file
36731  std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
36732 
36733  // Check that the file actually opened correctly
36734  if (!poly_file.is_open())
36735  {
36736  std::string error_msg("Failed to open poly file: ");
36737  error_msg += "\"" + poly_file_name + "\".";
36738  throw OomphLibError(
36739  error_msg, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36740  }
36741 
36742  // Number of nodes in poly file --- these will be ignore
36743  unsigned n_node_poly;
36744  poly_file >> n_node_poly;
36745 
36746  // Dimension
36747  poly_file >> dimension;
36748 
36749  // Attribute flag
36750  unsigned attribute_flag;
36751  poly_file >> attribute_flag;
36752 
36753  // Flag for boundary markers
36754  poly_file >> boundary_markers_flag;
36755 
36756  // Ignore node information: Note: No, we can't extract the
36757  // actual nodes themselves from here!
36758  unsigned dummy;
36759  for (unsigned i = 0; i < n_node_poly; i++)
36760  {
36761  // Read in (and discard) node number and x and y coordinates
36762  poly_file >> dummy;
36763  poly_file >> dummy;
36764  poly_file >> dummy;
36765  // read in the attributes
36766  for (unsigned j = 0; j < attribute_flag; ++j)
36767  {
36768  poly_file >> dummy;
36769  }
36770  // read in the boundary marker
36771  if (boundary_markers_flag == 1)
36772  {
36773  poly_file >> dummy;
36774  }
36775  }
36776 
36777  // Variable used to read the values from the input file
36778  unsigned read_value;
36779 
36780  // Number of segments
36781  poly_file >> read_value;
36782  const unsigned nglobal_segments = read_value;
36783 
36784  // Boundary marker flag
36785  poly_file >> boundary_markers_flag;
36786 
36787  // Global segment number
36788  unsigned global_segment_number;
36789 
36790  // Node identifier set (used to identify possible internal boundaries)
36791  std::set<unsigned> nodes_ids;
36792 
36793  // Extract information for each segment
36794  for (unsigned i = 0; i < nglobal_segments; i++)
36795  {
36796  // Node id on the edge of the segment
36797  unsigned lnode_id = 0; // left node
36798  unsigned rnode_id = 0; // right node
36799  unsigned bnd_id = 0; // boundary id associated to the current segment
36800  poly_file >> global_segment_number;
36801  poly_file >> lnode_id;
36802  poly_file >> rnode_id;
36803  nodes_ids.insert(lnode_id);
36804  nodes_ids.insert(rnode_id);
36805  if (boundary_markers_flag)
36806  {
36807  poly_file >> bnd_id;
36808  }
36809 
36810  // Store the segments info. (use bnd_id - 1 because the nodes and
36811  // elements associated the bnd_id have been associated by external
36812  // methods to bnd_id - 1)
36813  unsorted_boundary_segments[bnd_id - 1].push_back(
36814  std::make_pair(lnode_id, rnode_id));
36815 
36816  // Add the boundary id to the vector of boundaries ids only if it
36817  // has not been added, the polylines will be created using this
36818  // order
36819 
36820  // Get the number of boundaries ids currently sorted
36821  const unsigned nsorted_boundaries_ids = sorted_boundaries_ids.size();
36822  // Flag to know if the boundary id was found
36823  bool boundary_id_found = false;
36824  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36825  {
36826  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36827  {
36828  boundary_id_found = true;
36829  break;
36830  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36831  } // for (ib < nsorted_boundaries_ids)
36832 
36833  // If th boundary id has not been added, then add it!!!
36834  if (!boundary_id_found)
36835  {
36836  sorted_boundaries_ids.push_back(bnd_id - 1);
36837  } // if (!boundary_id_found)
36838  }
36839 
36840  // Verify if there are internal boundaries defined, if that is the
36841  // case we can not continue since we are not yet supporting internal
36842  // boundaries defined in polyfiles to created a mesh that may be
36843  // adapted
36844 #ifdef PARANOID
36845  if (nglobal_segments != nodes_ids.size())
36846  {
36847  std::ostringstream error_message;
36848  error_message
36849  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36850  << nglobal_segments << ") is different.\nThis may mean that there "
36851  << "are internal non-closed boundaries defined in\nthe polyfile. "
36852  << "If you need this feature please use the TriangleMeshPoyLine\n"
36853  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36854  throw OomphLibError(
36855  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36856  }
36857 #endif
36858 
36859  // Now sort the segments associated to a boundary to create a contiguous
36860  // polyline, but first check that the number of found boundaries be the
36861  // same as the current number of boundaries in the mesh
36862  const unsigned nboundary = unsorted_boundary_segments.size();
36863 
36864 #ifdef PARANOID
36865  if (nboundary != this->nboundary())
36866  {
36867  std::ostringstream error_message;
36868  error_message
36869  << "The number of boundaries on the mesh (" << this->nboundary()
36870  << ") is different from the number of\nboundaries read from the "
36871  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36872  throw OomphLibError(
36873  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36874  }
36875 #endif
36876 
36877  // Get the number of sorted boundaries ids and check that it matches
36878  // with the total number of boundaries
36879  const unsigned nsorted_boundaries_ids = sorted_boundaries_ids.size();
36880 #ifdef PARANOID
36881  if (nsorted_boundaries_ids != this->nboundary())
36882  {
36883  std::ostringstream error_message;
36884  error_message
36885  << "The number of boundaries on the mesh (" << this->nboundary()
36886  << ") is different from the number of\nsorted boundaries ids read "
36887  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36888  throw OomphLibError(
36889  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36890  }
36891 #endif
36892 
36893  // Sorted segments (to create a polyline -- boundary)
36894  std::map<unsigned, std::list<unsigned>> sorted_boundary_segments;
36895 
36896  // Go through all the found boundaries
36897  std::map<unsigned, Vector<std::pair<unsigned, unsigned>>>::iterator it;
36898 
36899  for (it = unsorted_boundary_segments.begin();
36900  it != unsorted_boundary_segments.end();
36901  it++)
36902  {
36903  // Get the current boundary id, only look for the segments
36904  // associated with this boundary
36905  const unsigned bnd_id = (*it).first;
36906  Vector<std::pair<unsigned, unsigned>> segments_edges = (*it).second;
36907 
36908  // Now sort the segments associated to this boundary
36909  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36910  const unsigned nsegments = segments_edges.size();
36911 
36912  // Sorted nodes for the current segment
36913  std::list<unsigned> sorted_segments;
36914 
36915  // Get the left and right node of the zero segment
36916  unsigned left_node_id = segments_edges[0].first;
36917  unsigned right_node_id = segments_edges[0].second;
36918 
36919  // ... and add it to the sorted segments structure
36920  sorted_segments.push_back(left_node_id);
36921  sorted_segments.push_back(right_node_id);
36922 
36923  // Mark the current segment as done
36924  segment_done[segments_edges[0]] = true;
36925 
36926  // Set the number of sorted segments
36927  unsigned nsorted_segments = 1;
36928 
36929  while (nsorted_segments < nsegments)
36930  {
36931  for (unsigned i = 1; i < nsegments; i++)
36932  {
36933  // Check if the i-th segments has been done
36934  if (!segment_done[segments_edges[i]])
36935  {
36936  // Get the left and right node id
36937  unsigned current_left_node_id = segments_edges[i].first;
36938  unsigned current_right_node_id = segments_edges[i].second;
36939 
36940  // Now check if the current segment can be added to the left
36941  // or right side of the sorted segments
36942  if (current_left_node_id == right_node_id)
36943  {
36944  // Add the current_right_node_id to the right of the sorted
36945  // segments
36946  sorted_segments.push_back(current_right_node_id);
36947  // Increase the number of sorted segments
36948  nsorted_segments++;
36949  // Mark the segment as done
36950  segment_done[segments_edges[i]] = true;
36951  // Update the right most node
36952  right_node_id = current_right_node_id;
36953  // Break the for loop
36954  break;
36955  }
36956  else if (current_right_node_id == left_node_id)
36957  {
36958  // Add the current_left_node_id to the left of the sorted
36959  // segments
36960  sorted_segments.push_front(current_left_node_id);
36961  // Increase the number of sorted segments
36962  nsorted_segments++;
36963  // Mark the segment as done
36964  segment_done[segments_edges[i]] = true;
36965  // Update the left most node
36966  left_node_id = current_left_node_id;
36967  // Break the for loop
36968  break;
36969  }
36970  else if (current_left_node_id == left_node_id)
36971  {
36972  // Add the current_right_node_id to the left of the sorted
36973  // segments
36974  sorted_segments.push_front(current_right_node_id);
36975  // Increase the number of sorted segments
36976  nsorted_segments++;
36977  // Mark the segment as done
36978  segment_done[segments_edges[i]] = true;
36979  // Update the left most node
36980  left_node_id = current_right_node_id;
36981  // Break the for loop
36982  break;
36983  }
36984  else if (current_right_node_id == right_node_id)
36985  {
36986  // Add the current_left_node_id to the right of the sorted
36987  // segments
36988  sorted_segments.push_back(current_left_node_id);
36989  // Increase the number of sorted segments
36990  nsorted_segments++;
36991  // Mark the segment as done
36992  segment_done[segments_edges[i]] = true;
36993  // Update the left most node
36994  right_node_id = current_left_node_id;
36995  // Break the for loop
36996  break;
36997  }
36998  } // if (!segment_done[segments_edges[i]])
36999  } // for (i < nsegments)
37000  } // while(nsorted_segments < nsegments)
37001 
37002  sorted_boundary_segments[bnd_id] = sorted_segments;
37003 
37004  } // for (unsorted_boundary_segments.begin();
37005  // unsorted_boundary_segments.end())
37006 
37007 #ifdef PARANOID
37008  if (sorted_boundary_segments.size() != this->nboundary())
37009  {
37010  std::ostringstream error_message;
37011  error_message
37012  << "The number of boundaries on the mesh (" << this->nboundary()
37013  << ") is different from the number\nof sorted boundaries to create the "
37014  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
37015  throw OomphLibError(
37016  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37017  }
37018 #endif
37019 
37020  // Now we have the sorted nodes, we can create the polylines by
37021  // getting the vertices of the nodes
37022  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
37023  unsigned current_polyline = 0;
37024 
37025  // Go through the sorted boundaries using the sorted boundaries ids
37026  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
37027  {
37028  // Get the boundary id from the vector of sorted boundaries ids
37029  const unsigned bnd_id = sorted_boundaries_ids[ib];
37030 
37031  // Create a vector representation for ease to use
37032  // Get the vertices of the nodes that create the boundary / polyline
37033  Vector<unsigned> nodes_ids;
37034  for (std::list<unsigned>::iterator it_list =
37035  sorted_boundary_segments[bnd_id].begin();
37036  it_list != sorted_boundary_segments[bnd_id].end();
37037  it_list++)
37038  {
37039  nodes_ids.push_back((*it_list));
37040  }
37041 
37042  // Get the number of vertices for the polyline
37043  const unsigned nvertices = nodes_ids.size();
37044 
37045  // The storage for the vertices
37046  Vector<Vector<double>> vertices(nvertices);
37047 
37048  // Now get the vertices of the nodes of the current boundary
37049  for (unsigned i = 0; i < nvertices; i++)
37050  {
37051  // Get the vertices
37052  vertices[i].resize(2);
37053  vertices[i][0] = x_node[nodes_ids[i] - 1];
37054  vertices[i][1] = y_node[nodes_ids[i] - 1];
37055  }
37056 
37057  // Now create the polyline
37058 
37059  // Note: The bnd_id is the real bnd_id (from the input file) - 1
37060  // since nodes and elements of the current boundary have been
37061  // associated to bnd_id - 1)
37062  polylines_pt[current_polyline] =
37063  new TriangleMeshPolyLine(vertices, bnd_id);
37064 
37065  // Updates bnd_id<--->curve section map
37066  this->Boundary_curve_section_pt[bnd_id] =
37067  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
37068 
37069  // Increase the index for the polyline storage
37070  current_polyline++;
37071 
37072  } // for (it_sorted = sorted_boundary_segments.begin();
37073  // it_sorted != sorted_boundary_segments.end())
37074 
37075  // Now create the polygons or closed curves
37076  // Sort the polylines to create polygons
37077  unsigned nsorted_polylines = 0;
37078 
37079  // Number of created polygons
37080  unsigned npolygons = 0;
37081 
37082  // Storage for the polygons
37083  Vector<TriangleMeshPolygon*> polygons_pt;
37084 
37085  // Mark the already done polylines
37086  std::map<unsigned, bool> polyline_done;
37087  while (nsorted_polylines < nboundary)
37088  {
37089  // Storage for the curve sections that create a polygon
37090  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
37091 
37092  unsigned init_poly = 0;
37093 #ifdef PARANOID
37094  bool found_root_polyline = false;
37095 #endif
37096  // Get the left and right node of the current polyline
37097  for (unsigned i = 0; i < nboundary; i++)
37098  {
37099  if (!polyline_done[i])
37100  {
37101  init_poly = i;
37102  // Increase the number of sorted polylines
37103  nsorted_polylines++;
37104 #ifdef PARANOID
37105  // Mark as found the root polyline
37106  found_root_polyline = true;
37107 #endif
37108  // Mark the polyline as done
37109  polyline_done[i] = true;
37110  // Add the polyline to the curve sections storage
37111  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37112  // Break the loop to set we have found a root polyline
37113  break;
37114  }
37115  }
37116 
37117 #ifdef PARANOID
37118  if (!found_root_polyline)
37119  {
37120  std::ostringstream error_message;
37121  error_message << "Was not possible to found the root polyline to "
37122  "create polygons\n\n";
37123  throw OomphLibError(error_message.str(),
37124  OOMPH_CURRENT_FUNCTION,
37125  OOMPH_EXCEPTION_LOCATION);
37126  }
37127 #endif
37128 
37129  // Get the associated boundary to the current polyline
37130  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
37131  // Get the initial and final node id of the current polyline
37132  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
37133  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
37134 
37135  // Flag to know that we already have a closed polygon
37136  bool closed_polygon = false;
37137 
37138  do
37139  {
37140  // Go through all the polylines
37141  for (unsigned i = init_poly; i < nboundary; i++)
37142  {
37143  // Check that the polyline has not been currently done
37144  if (!polyline_done[i])
37145  {
37146  // Get the initial and final nodes id of the current polyline
37147 
37148  // Get the associated boundary to the current polyline
37149  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
37150  // Get the initial and final node id of the current polyline
37151  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
37152  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
37153 
37154  // Check if the polyline goes to the left or right of the
37155  // current sorted polylines
37156  if (cleft_node_id == right_node_id)
37157  {
37158  // Add the polyline to the curve section storage
37159  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37160  // Mark the polyline as done
37161  polyline_done[i] = true;
37162  // Update the right node
37163  right_node_id = cright_node_id;
37164  // Increase the number of done polyines
37165  nsorted_polylines++;
37166  // Break the for loop
37167  break;
37168  }
37169  else if (cright_node_id == left_node_id)
37170  {
37171  // Add the polyline to the curve section storage
37172  sorted_curve_sections_pt.push_front(polylines_pt[i]);
37173  // Mark the polyline as done
37174  polyline_done[i] = true;
37175  // Update the right node
37176  left_node_id = cleft_node_id;
37177  // Increase the number of done polyines
37178  nsorted_polylines++;
37179  // Break the for loop
37180  break;
37181  }
37182  else if (cleft_node_id == left_node_id)
37183  {
37184  // First reverse the polyline
37185  polylines_pt[i]->reverse();
37186  // Add the polyline to the curve section storage
37187  sorted_curve_sections_pt.push_front(polylines_pt[i]);
37188  // Mark the polyline as done
37189  polyline_done[i] = true;
37190  // Update the right node
37191  left_node_id = cright_node_id;
37192  // Increase the number of done polyines
37193  nsorted_polylines++;
37194  // Break the for loop
37195  break;
37196  }
37197  else if (cright_node_id == right_node_id)
37198  {
37199  // First reverse the polyline
37200  polylines_pt[i]->reverse();
37201  // Add the polyline to the curve section storage
37202  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37203  // Mark the polyline as done
37204  polyline_done[i] = true;
37205  // Update the right node
37206  right_node_id = cleft_node_id;
37207  // Increase the number of done polyines
37208  nsorted_polylines++;
37209  // Break the for loop
37210  break;
37211  }
37212  } // if (!polyline_done[i])
37213 
37214  } // for (i < nboundary)
37215 
37216  // We have created a polygon
37217  if (left_node_id == right_node_id)
37218  {
37219  // Set the flag as true
37220  closed_polygon = true;
37221  }
37222 
37223  } while (nsorted_polylines < nboundary && !closed_polygon);
37224 
37225 #ifdef PARANOID
37226  if (!closed_polygon)
37227  {
37228  std::ostringstream error_message;
37229  error_message
37230  << "It was not possible to create a closed curve, these are the "
37231  << "vertices of the already sorted polylines\n\n";
37232  unsigned cpolyline = 0;
37233  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37234  sorted_curve_sections_pt.begin();
37235  it_list != sorted_curve_sections_pt.end();
37236  it_list++)
37237  {
37238  error_message << "Polyline (" << cpolyline << ")\n";
37239  TriangleMeshPolyLine* tmp_poly_pt =
37240  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
37241  const unsigned nvertex = tmp_poly_pt->nvertex();
37242  for (unsigned v = 0; v < nvertex; v++)
37243  {
37244  error_message << "(" << tmp_poly_pt->vertex_coordinate(v)[0] << ", "
37245  << tmp_poly_pt->vertex_coordinate(v)[1] << ")\n";
37246  }
37247  error_message << "\n";
37248  cpolyline++;
37249  }
37250  throw OomphLibError(error_message.str(),
37251  OOMPH_CURRENT_FUNCTION,
37252  OOMPH_EXCEPTION_LOCATION);
37253  }
37254 #endif
37255 
37256  // Create a vector version to create the polygon from the sorted
37257  // polyines
37258  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37259  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37260  sorted_curve_sections_pt.begin();
37261  it_list != sorted_curve_sections_pt.end();
37262  it_list++)
37263  {
37264  tmp_sorted_curve_sections_pt.push_back((*it_list));
37265  }
37266 
37267  // Create a new polygon by using the new created polylines
37268  TriangleMeshPolygon* polygon_pt =
37269  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37270 
37271  // Keep track of new created polygons that need to be deleted!!!
37272  this->Free_polygon_pt.insert(polygon_pt);
37273 
37274  // Store the polygon in the polygons storages
37275  polygons_pt.push_back(polygon_pt);
37276 
37277  npolygons++;
37278 
37279  } // while(nsorted_polylines < nboundary)
37280 
37281  // ------------------------------------------------------------------
37282  // Before filling the data structures we need to identify the outer
37283  // closed boundary and the inner closed boundaries.
37284  // If the nodes are not in order we throw a warning message
37285 
37286  // Index for the polygon that is currently considered as the outer
37287  // boundary
37288  unsigned index_outer = 0;
37289 
37290  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37291  {
37292  // Get the vertices of the outer boundary
37293  Vector<Vector<double>> outer_vertex_coordinates;
37294 
37295  // Flag to know if ALL the inner closed boundaries are inside the
37296  // outer closed boundary
37297  bool all_inner_inside = true;
37298 
37299  // Number of polylines of the outer boundary
37300  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37301  for (unsigned p = 0; p < nouter_polylines; p++)
37302  {
37303  TriangleMeshPolyLine* tmp_poly_pt =
37304  polygons_pt[idx_outer]->polyline_pt(p);
37305  const unsigned nvertex = tmp_poly_pt->nvertex();
37306  for (unsigned v = 0; v < nvertex; v++)
37307  {
37308  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37309  outer_vertex_coordinates.push_back(current_vertex);
37310  } // for (v < nvertex)
37311  } // for (p < nouter_polylines)
37312 
37313  // Now get the vertices for the inner boundaries
37314 
37315  // First get the number of inner closed boundaries (polygons size
37316  // minus one because one of the polygons is considered to be the
37317  // outer closed boundary
37318  const unsigned ninner_polygons = polygons_pt.size() - 1;
37319 
37320  // Store the vertices of the inner closed boundaries
37321  Vector<Vector<Vector<double>>> inner_vertex_coordinates(ninner_polygons);
37322  // Get all the vertices of the inner closed boundaries
37323  for (unsigned i = 0; i <= ninner_polygons; i++)
37324  {
37325  if (i != idx_outer)
37326  {
37327  // Number of polylines of the current internal closed boundary
37328  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37329  for (unsigned p = 0; p < ninner_polylines; p++)
37330  {
37331  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37332  const unsigned nvertex = tmp_poly_pt->nvertex();
37333  for (unsigned v = 0; v < nvertex; v++)
37334  {
37335  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37336  if (i < idx_outer)
37337  {
37338  inner_vertex_coordinates[i].push_back(current_vertex);
37339  }
37340  else if (i > idx_outer)
37341  {
37342  inner_vertex_coordinates[i - 1].push_back(current_vertex);
37343  }
37344  } // for (v < nvertex)
37345 
37346  } // for (p < ninner_polylines)
37347 
37348  } // if (i != index_outer)
37349 
37350  } // for (i <= ninner_polygons)
37351 
37352  // Now check that ALL the vertices of ALL the internal closed
37353  // boundaries are inside the outer closed boundary
37354  for (unsigned i = 0; i < ninner_polygons; i++)
37355  {
37356  // Get the number of vertices in the current internal closed
37357  // boundary
37358  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37359  for (unsigned v = 0; v < nvertex_internal; v++)
37360  {
37361  // Get a vertex in the current internal closed boundary
37362  Vector<double> current_point = inner_vertex_coordinates[i][v];
37363  all_inner_inside &= this->is_point_inside_polygon_helper(
37364  outer_vertex_coordinates, current_point);
37365 
37366  // Check if we should continue checking for more points inside
37367  // the current proposed outer boundary
37368  if (!all_inner_inside)
37369  {
37370  // Break the "for" for the vertices
37371  break;
37372  }
37373 
37374  } // for (v < nvertex_internal)
37375 
37376  // Check if we should continue checking for more inner closed
37377  // boundaries inside the current proposed outer boundary
37378  if (!all_inner_inside)
37379  {
37380  // Break the "for" for the inner boundaries
37381  break;
37382  }
37383 
37384  } // for (i < ninner_polygons)
37385 
37386  // Check if all the vertices of all the polygones are inside the
37387  // current proposed outer boundary
37388  if (all_inner_inside)
37389  {
37390  index_outer = idx_outer;
37391  break;
37392  }
37393 
37394  } // for (idx_outer < npolygons)
37395 
37396 #ifdef PARANOID
37397  // Check if the first nodes listed in the polyfiles correspond to
37398  // the outer boundary, if that is not the case then throw a warning
37399  // message
37400  if (index_outer != 0)
37401  {
37402  std::ostringstream warning_message;
37403  warning_message
37404  << "The first set of nodes listed in the input polyfiles does not\n"
37405  << "correspond to the outer closed boundary. This may lead to\n"
37406  << "problems at the adaptation stage if the holes coordinates\n"
37407  << "are no correctly associated to the inner closed boundaries.\n"
37408  << "You can check the generated mesh by calling the output() method\n"
37409  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37410  OomphLibWarning(warning_message.str(),
37411  OOMPH_CURRENT_FUNCTION,
37412  OOMPH_EXCEPTION_LOCATION);
37413  } // if (index_outer != 0)
37414 #endif
37415 
37416  // ------------------------------------------------------------------
37417  // Now fill the data structures
37418 
37419  // Store outer polygon
37420  // We are assuming there is only one outer polygon
37421  this->Outer_boundary_pt.resize(1);
37422  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37423 
37424  this->Internal_polygon_pt.resize(npolygons - 1);
37425  for (unsigned i = 0; i < npolygons; i++)
37426  {
37427  if (i != index_outer)
37428  {
37429  if (i < index_outer)
37430  {
37431  // Store internal polygons by copy constructor
37432  this->Internal_polygon_pt[i] = polygons_pt[i];
37433  }
37434  else if (i > index_outer)
37435  {
37436  // Store internal polygons by copy constructor
37437  this->Internal_polygon_pt[i - 1] = polygons_pt[i];
37438  }
37439  } // if (i != index_outer)
37440  } // for (i < npolygons)
37441 
37442  // Before assigning the hole vertex coordinate to the inner closed
37443  // boundaries check that the holes are listed in orderm if that is
37444  // not the case the associate each hole vertex coordinate to the
37445  // inner closed boundaries
37446 
37447  // Store the vertices of the inner closed boundaries
37448  Vector<Vector<Vector<double>>> inner_vertex_coordinates(npolygons - 1);
37449  // Get all the vertices of the inner closed boundaries
37450  for (unsigned i = 0; i < npolygons - 1; i++)
37451  {
37452  // Number of polylines of the current internal closed boundary
37453  const unsigned ninner_polylines =
37454  this->Internal_polygon_pt[i]->npolyline();
37455  for (unsigned p = 0; p < ninner_polylines; p++)
37456  {
37457  TriangleMeshPolyLine* tmp_poly_pt =
37458  this->Internal_polygon_pt[i]->polyline_pt(p);
37459  // Number of vertices of the current polyline in the current
37460  // internal closed polygon
37461  const unsigned nvertex = tmp_poly_pt->nvertex();
37462  for (unsigned v = 0; v < nvertex; v++)
37463  {
37464  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37465  inner_vertex_coordinates[i].push_back(current_vertex);
37466  } // for (v < nvertex)
37467 
37468  } // for (p < ninner_polylines)
37469 
37470  } // for (i <= ninner_polygons)
37471 
37472  // Holes information
37473  unsigned nholes;
37474  poly_file >> nholes;
37475 
37476 #ifdef PARANOID
37477  if (npolygons > 1 && (npolygons - 1) != nholes)
37478  {
37479  std::ostringstream error_message;
37480  error_message
37481  << "The number of holes (" << nholes << ") does not correspond "
37482  << "with the number\nof internal polygons (" << npolygons - 1 << ")\n\n"
37483  << "Using polyfiles as input does not currently allows the\n"
37484  << "definition of more than one outer polygon\n\n";
37485  throw OomphLibError(
37486  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37487  }
37488 #endif
37489 
37490  // Storage for the holes
37491  Vector<Vector<double>> hole_coordinates(nholes);
37492 
37493  // Dummy for hole number
37494  unsigned dummy_hole;
37495  // Loop over the holes to get centre coords
37496  for (unsigned ihole = 0; ihole < nholes; ihole++)
37497  {
37498  hole_coordinates[ihole].resize(2);
37499  // Read the centre value
37500  poly_file >> dummy_hole;
37501  poly_file >> hole_coordinates[ihole][0];
37502  poly_file >> hole_coordinates[ihole][1];
37503  }
37504 
37505  // Vector that store the index of the hole coordinate that
37506  // correspond to each internal closed polygon
37507  Vector<unsigned> index_hole_of_internal_polygon(npolygons - 1);
37508  std::map<unsigned, bool> hole_done;
37509 
37510  // Now associate each hole vertex to a corresponding internal closed
37511  // polygon
37512  for (unsigned i = 0; i < npolygons - 1; i++)
37513  {
37514  // Find which hole is associated to each internal closed boundary
37515  for (unsigned h = 0; h < nholes; h++)
37516  {
37517  // If the hole has not been previously associated
37518  if (!hole_done[h])
37519  {
37520  // Get the hole coordinate
37521  Vector<double> current_point = hole_coordinates[h];
37522 
37523  const bool hole_in_polygon = this->is_point_inside_polygon_helper(
37524  inner_vertex_coordinates[i], current_point);
37525 
37526  // If the hole is inside the polygon
37527  if (hole_in_polygon)
37528  {
37529  // Mark the hole as done
37530  hole_done[h] = true;
37531  // Associate the current hole with the current inner closed
37532  // boundary
37533  index_hole_of_internal_polygon[i] = h;
37534  // Break the search
37535  break;
37536  }
37537 
37538  } // if (!hole_done[h])
37539 
37540  } // for (h < nholes)
37541 
37542  } // for (i < npolygons-1)
37543 
37544 #ifdef PARANOID
37545  if (hole_done.size() != npolygons - 1)
37546  {
37547  std::ostringstream error_message;
37548  error_message
37549  << "Not all the holes were associated to an internal closed boundary\n"
37550  << "Only (" << hole_done.size()
37551  << ") holes were assigned for a total of\n"
37552  << "(" << npolygons - 1 << ") internal closed boundaries.\n"
37553  << "You can check the generated mesh by calling the output() method\n"
37554  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37555  throw OomphLibError(
37556  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37557  } // if (index_hole != ihole)
37558 #endif
37559 
37560  // Assign the holes coordinates to the internal polygons
37561  for (unsigned ihole = 0; ihole < nholes; ihole++)
37562  {
37563  // Get the index hole of the current internal closed polygon
37564  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37565 #ifdef PARANOID
37566  // Check if the hole index is the same as the internal closed
37567  // boundary, it means that the holes were listed in the same order
37568  // as the nodes of the internal closed boundaries
37569  if (index_hole != ihole)
37570  {
37571  std::ostringstream error_message;
37572  error_message
37573  << "The hole vertices coordinates are not listed in the same order\n"
37574  << "as the nodes that define the internal closed boundaries.\n"
37575  << "This may lead to problems in case that the holes coordinates\n"
37576  << "were no properly assigned to the internal closed boundaries.\n"
37577  << "You can check the generated mesh by calling the output() method\n"
37578  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37579  throw OomphLibError(error_message.str(),
37580  OOMPH_CURRENT_FUNCTION,
37581  OOMPH_EXCEPTION_LOCATION);
37582  } // if (index_hole != ihole)
37583 #endif
37584 
37585  // Set the hole coordinate for the internal polygon
37586  this->Internal_polygon_pt[ihole]->internal_point() =
37587  hole_coordinates[index_hole];
37588  }
37589 
37590  // Ignore the first line with structure description
37591  poly_file.ignore(80, '\n');
37592 
37593  // Regions information
37594  unsigned nregions;
37595 
37596  // Extract regions information
37597  // But first check if there are regions or not
37598  std::string regions_info_string;
37599 
37600  // Read line up to termination sign
37601  getline(poly_file, regions_info_string);
37602 
37603  // Check if the read string is a number or a comment wrote by triangle,
37604  // if it is a number then that is the number of regions
37605  if (isdigit(regions_info_string.c_str()[0]))
37606  {
37607  nregions = std::atoi(regions_info_string.c_str());
37608  }
37609  else
37610  {
37611  nregions = 0;
37612  }
37613 
37614  // The regions coordinates
37615  std::map<unsigned, Vector<double>> regions_coordinates;
37616 
37617  // Dummy for regions number
37618  unsigned dummy_region;
37619 
37620  unsigned region_id;
37621 
37622  // Loop over the regions to get their coords
37623  for (unsigned iregion = 0; iregion < nregions; iregion++)
37624  {
37625  Vector<double> tmp_region_coordinates(2);
37626  // Read the regions coordinates
37627  poly_file >> dummy_region;
37628  poly_file >> tmp_region_coordinates[0];
37629  poly_file >> tmp_region_coordinates[1];
37630  poly_file >> region_id;
37631  regions_coordinates[region_id].resize(2);
37632  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37633  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37634 
37635  // Ignore the first line with structure description
37636  poly_file.ignore(80, '\n');
37637 
37638  // Verify if not using the default region number (zero)
37639  if (region_id == 0)
37640  {
37641  std::ostringstream error_message;
37642  error_message
37643  << "Please use another region id different from zero.\n"
37644  << "It is internally used as the default region number.\n";
37645  throw OomphLibError(error_message.str(),
37646  OOMPH_CURRENT_FUNCTION,
37647  OOMPH_EXCEPTION_LOCATION);
37648  }
37649  }
37650 
37651  // Store the extra regions coordinates
37652  this->Regions_coordinates = regions_coordinates;
37653 
37654  poly_file.close();
37655  }
37656 
37657  //======================================================================
37658  /// \short Updates the polygon but using the elements area instead of
37659  /// the default refinement and unrefinement methods
37660  //======================================================================
37661  template<class ELEMENT>
37663  TriangleMeshPolygon*& polygon_pt, const Vector<double>& target_area)
37664  {
37665  // Verify that there was a change on the polygon representation
37666  unsigned update_was_performed = false;
37667 
37668  const unsigned nele = this->nelement();
37669 
37670  // - Get the vertices along the boundaries and for each element identify
37671  // its associated target error.
37672  // - Get face mesh representation of each polyline.
37673  // - Get the vertices with the help of face elements.
37674  // - Find the global index in the mesh of the face element and use
37675  // it to get its associated target area
37676 
37677  // Get the face mesh representation
37678  Vector<Mesh*> face_mesh_pt;
37679  get_face_mesh_representation(polygon_pt, face_mesh_pt);
37680 
37681  // Create vertices of the polylines by using the vertices of the
37682  // FaceElements
37683  Vector<double> vertex_coord(3); // zeta,x,y
37684  Vector<double> bound_left(1);
37685  Vector<double> bound_right(1);
37686 
37687  unsigned n_polyline = polygon_pt->npolyline();
37688 
37689  // Go for each polyline
37690  for (unsigned p = 0; p < n_polyline; p++)
37691  {
37692  // Get the MeshAsGeomObject representation just once per polyline,
37693  // this object is only used by the
37694  // refine_boundary_constrained_by_target_area() method. We get it
37695  // here to ensure that all processors (in a distributed context)
37696  // get this representation just once, and because an AllToAll MPI
37697  // communication is used in this calling
37698  MeshAsGeomObject* mesh_geom_obj_pt =
37699  new MeshAsGeomObject(face_mesh_pt[p]);
37700 
37701  // Set of coordinates on the boundary
37702  // Set entries are ordered on first entry in vector which stores
37703  // the boundary coordinate so the vertices come out in order!
37704  std::set<Vector<double>> vertex_nodes;
37705 
37706  // Vector to store the vertices, transfer the sorted vertices from the
37707  // set to this vector, --- including the z-value ---
37708  Vector<Vector<double>> tmp_vector_vertex_node;
37709 
37710  // Vector to store the coordinates of the polylines, same as the
37711  // tmp_vector_vertex_node vector (after adding more nodes) but
37712  // --- without the z-value ---, used to re-generate the polylines
37713  Vector<Vector<double>> vector_vertex_node;
37714 
37715 #ifdef OOMPH_HAS_MPI
37716  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37717  // Set of coordinates that are on the boundary (splitted boundary version)
37718  // The first vector is used to allocate the points for each sub-boundary
37719  // Set entries are ordered on first entry in vector which stores
37720  // the boundary coordinate so the vertices come out in order!
37721  Vector<std::set<Vector<double>>> sub_vertex_nodes;
37722 
37723  // Vector to store the vertices, transfer the sorted vertices from the
37724  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37725  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
37726 
37727  // Vector to store the coordinates of the polylines that will represent
37728  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37729  // but --- without the z-value ---, used to generate the sub-polylines
37730  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
37731  // --------- Stuff to deal with splitted boundaries ----------- End ------
37732 #endif
37733 
37734  // Get the boundary id
37735  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37736 
37737  // Get the chunk number
37738  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37739 
37740  /// Use a vector of vector for vertices and target areas to deal
37741  /// with the cases when the boundaries are split by the
37742  /// distribution process
37743 
37744  // Loop over the face elements (ordered) and add their vertices
37745  const unsigned nface_element = face_mesh_pt[p]->nelement();
37746 
37747  // Store the non halo face elements, the ones from which we will
37748  // get the vertices
37749  Vector<FiniteElement*> non_halo_face_element_pt;
37750 
37751  // Map to store the index of the face element on a boundary
37752  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
37753 
37754  for (unsigned ef = 0; ef < nface_element; ++ef)
37755  {
37756  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37757 #ifdef OOMPH_HAS_MPI
37758  // Skip the halo elements if working with a distributed mesh
37759  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37760  {
37761  continue;
37762  }
37763 #endif
37764  // Add the face element to the vector
37765  non_halo_face_element_pt.push_back(ele_face_pt);
37766  face_element_index_on_boundary[ele_face_pt] = ef;
37767  }
37768 
37769  // Get the number of non halo face element
37770  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37771 
37772  // Map to know the already sorted face elements
37773  std::map<FiniteElement*, bool> face_element_done;
37774 
37775  // Number of done face elements
37776  unsigned nsorted_face_elements = 0;
37777 
37778 #ifdef OOMPH_HAS_MPI
37779  // Counter for sub_boundaries
37780  unsigned nsub_boundaries = 0;
37781 #endif // #ifdef OOMPH_HAS_MPI
37782 
37783  // Continue until all the face elements have been sorted
37784  // While to deal with split boundaries cases
37785  while (nsorted_face_elements < nnon_halo_face_element)
37786  {
37787  // Get and initial face element
37788  FiniteElement* ele_face_pt = 0;
37789 #ifdef PARANOID
37790  bool found_initial_face_element = false;
37791 #endif
37792 
37793  unsigned iface = 0;
37794  for (iface = 0; iface < nnon_halo_face_element; iface++)
37795  {
37796  ele_face_pt = non_halo_face_element_pt[iface];
37797  // If not done then take it as initial face element
37798  if (!face_element_done[ele_face_pt])
37799  {
37800 #ifdef PARANOID
37801  found_initial_face_element = true;
37802 #endif
37803  nsorted_face_elements++;
37804  iface++;
37805  break;
37806  }
37807  }
37808 
37809 #ifdef PARANOID
37810  if (!found_initial_face_element)
37811  {
37812  std::ostringstream error_message;
37813  error_message << "Could not find an initial face element for the "
37814  "current segment\n";
37815  // << "----- Possible memory leak -----\n";
37816  throw OomphLibError(
37817  error_message.str(),
37818  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37819  OOMPH_EXCEPTION_LOCATION);
37820  }
37821 #endif
37822 
37823  // Local set of coordinates that are on the boundary
37824  // Set entries are ordered on first entry in vector which stores
37825  // the boundary coordinate so the vertices come out in order!
37826  std::set<Vector<double>> local_vertex_nodes;
37827 
37828  // Vector to store the vertices, transfer the sorted vertices from the
37829  // set (local) to this vector (local), --- including the z-value ---
37830  Vector<Vector<double>> local_tmp_vector_vertex_node;
37831 
37832  // Vector to store the target areas, uses the same approach as the
37833  // set for the local_vertex_nodes, ordered on first entry
37834  std::set<Vector<double>> sorted_target_areas;
37835 
37836  // Vector to store the target areas, used to transfer the sorted target
37837  // areas from "local_sorted_target_areas" set
37838  Vector<double> tmp_sorted_target_areas;
37839 
37840  // -----------------------------------------------------------------
37841  // Add the vertices of the initial face element to the set of
37842  // local sorted vertices
37843  // -----------------------------------------------------------------
37844  unsigned nnode = ele_face_pt->nnode();
37845  // Add the left-hand node to the set:
37846  // Boundary coordinate
37847  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
37848  vertex_coord[0] = bound_left[0];
37849 
37850  // Actual coordinates
37851  for (unsigned i = 0; i < 2; i++)
37852  {
37853  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
37854  }
37855  local_vertex_nodes.insert(vertex_coord);
37856 
37857  // Add the right-hand nodes to the set:
37858  // Boundary coordinate
37859  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
37860  bound, bound_right);
37861  vertex_coord[0] = bound_right[0];
37862 
37863  // Actual coordinates
37864  for (unsigned i = 0; i < 2; i++)
37865  {
37866  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
37867  }
37868  local_vertex_nodes.insert(vertex_coord);
37869 
37870  // The initial and final node on the set
37871  Node* first_node_pt = ele_face_pt->node_pt(0);
37872  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
37873 
37874  // Mark the current face element as done
37875  face_element_done[ele_face_pt] = true;
37876 
37877  // -------------------------------------------------------
37878  // Find the global index in the mesh of the face element
37879  // and use it to get its associated target area
37880  // -------------------------------------------------------
37881  // Container to store the zeta value (used as index) and
37882  // the associated target area of the element
37883  Vector<double> zeta_target_area_values(2);
37884 
37885  // Use the minimum zeta value to sort the target areas
37886  // along the boundary
37887  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
37888 
37889  // Get the index of the face element on the current boundary
37890  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37891  // Get the "ef"-th element on the boundary
37892  FiniteElement* el_pt = this->boundary_element_pt(bound, ef);
37893 
37894 #ifdef PARANOID
37895  bool found_global_element_index = false;
37896 #endif
37897  for (unsigned eg = 0; eg < nele; eg++)
37898  {
37899  // Get the "eg-th" element
37900  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
37901 
37902  // Compare with the element on the boundary, if equal then
37903  // store the target area
37904  if (el_pt == el_compare_pt)
37905  {
37906  zeta_target_area_values[1] = target_area[eg];
37907 #ifdef PARANOID
37908  found_global_element_index = true;
37909 #endif
37910  break; // break the for (e < nele) global element
37911  } // if element_pt == element_compare_pt
37912  } // for nele (on complete mesh)
37913 
37914 #ifdef PARANOID
37915  if (!found_global_element_index)
37916  {
37917  std::ostringstream error_message;
37918  error_message << "The global index for the (" << ef
37919  << ")-th face element "
37920  << "on\nthe (" << bound
37921  << ")-th boundary was not found!!!";
37922  throw OomphLibError(
37923  error_message.str(),
37924  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37925  OOMPH_EXCEPTION_LOCATION);
37926  }
37927 #endif
37928 
37929  // Add the target areas to the sorted set
37930  sorted_target_areas.insert(zeta_target_area_values);
37931  // ------------------------------------------------------------------
37932 
37933  // Continue iterating if a new face element has been added to the
37934  // list
37935  bool face_element_added = false;
37936 
37937  // While a new face element has been added to the set of sorted
37938  // face elements then re-iterate
37939  do
37940  {
37941  // Start from the next face elements since we have already
37942  // added the previous one as the initial face element (any
37943  // previous face element had to be added on previous
37944  // iterations)
37945  for (unsigned iiface = iface; iiface < nnon_halo_face_element;
37946  iiface++)
37947  {
37948  face_element_added = false;
37949  ele_face_pt = non_halo_face_element_pt[iiface];
37950  if (!face_element_done[ele_face_pt])
37951  {
37952  // Get each individual node to check if they are contiguous
37953  nnode = ele_face_pt->nnode();
37954  Node* left_node_pt = ele_face_pt->node_pt(0);
37955  Node* right_node_pt = ele_face_pt->node_pt(nnode - 1);
37956 
37957  if (left_node_pt == first_node_pt)
37958  {
37959  first_node_pt = right_node_pt;
37960  face_element_added = true;
37961  }
37962  else if (left_node_pt == last_node_pt)
37963  {
37964  last_node_pt = right_node_pt;
37965  face_element_added = true;
37966  }
37967  else if (right_node_pt == first_node_pt)
37968  {
37969  first_node_pt = left_node_pt;
37970  face_element_added = true;
37971  }
37972  else if (right_node_pt == last_node_pt)
37973  {
37974  last_node_pt = left_node_pt;
37975  face_element_added = true;
37976  }
37977 
37978  if (face_element_added)
37979  {
37980  // Add the left-hand node to the set:
37981  // Boundary coordinate
37982  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
37983  vertex_coord[0] = bound_left[0];
37984 
37985  // Actual coordinates
37986  for (unsigned i = 0; i < 2; i++)
37987  {
37988  vertex_coord[i + 1] = left_node_pt->x(i);
37989  }
37990  local_vertex_nodes.insert(vertex_coord);
37991 
37992  // Add the right-hand nodes to the set:
37993  // Boundary coordinate
37994  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
37995  vertex_coord[0] = bound_right[0];
37996 
37997  // Actual coordinates
37998  for (unsigned i = 0; i < 2; i++)
37999  {
38000  vertex_coord[i + 1] = right_node_pt->x(i);
38001  }
38002  local_vertex_nodes.insert(vertex_coord);
38003 
38004  // Mark as done only if one of its nodes has been
38005  // added to the list
38006  face_element_done[ele_face_pt] = true;
38007  nsorted_face_elements++;
38008 
38009  // -----------------------------------------------------
38010  // Find the global index in the mesh of the face element
38011  // and use it to get its associated target area
38012  // -----------------------------------------------------
38013  // Use the minimum zeta value to sort the target areas
38014  // along the boundary
38015  zeta_target_area_values[0] =
38016  std::min(bound_left[0], bound_right[0]);
38017 
38018  // Get the "ef"-th element on the boundary
38019  ef = face_element_index_on_boundary[ele_face_pt];
38020  FiniteElement* lel_pt = this->boundary_element_pt(bound, ef);
38021 
38022 #ifdef PARANOID
38023  found_global_element_index = false;
38024 #endif
38025  for (unsigned eg = 0; eg < nele; eg++)
38026  {
38027  // Get the "eg-th" element
38028  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
38029 
38030  // Compare with the element on the boundary, if equal then
38031  // store the target area
38032  if (lel_pt == lel_compare_pt)
38033  {
38034  zeta_target_area_values[1] = target_area[eg];
38035 #ifdef PARANOID
38036  found_global_element_index = true;
38037 #endif
38038  break; // break the for (e < nele) global element
38039  } // if element_pt == element_compare_pt
38040  } // for nele (on complete mesh)
38041 
38042 #ifdef PARANOID
38043  if (!found_global_element_index)
38044  {
38045  std::ostringstream error_message;
38046  error_message << "The global index for the (" << ef
38047  << ")-th face element "
38048  << "on\nthe (" << bound
38049  << ")-th boundary was not found!!!";
38050  throw OomphLibError(error_message.str(),
38051  "RefineableTriangleMesh::update_polygon_"
38052  "using_elements_area()",
38053  OOMPH_EXCEPTION_LOCATION);
38054  }
38055 #endif
38056 
38057  // Add the target areas to the sorted set
38058  sorted_target_areas.insert(zeta_target_area_values);
38059 
38060  break;
38061  }
38062 
38063  } // if (!edge_done[edge])
38064  } // for (iiedge < nedges)
38065  } while (face_element_added &&
38066  (nsorted_face_elements < nnon_halo_face_element));
38067 
38068  // -----------------------------------------------------------------
38069  // At this point we already have a sorted set of nodes and
38070  // can be used to peform the unrefinement and refinement procedures
38071  // -----------------------------------------------------------------
38072 
38073  // Get the number of nodes on the list
38074  const unsigned nlocal_nodes = local_vertex_nodes.size();
38075  // Change representation to vector for easy of handling ...
38076  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38077 
38078  // Copy the vertices of the nodes
38079  unsigned counter = 0;
38080  std::set<Vector<double>>::iterator it_vertex;
38081  for (it_vertex = local_vertex_nodes.begin();
38082  it_vertex != local_vertex_nodes.end();
38083  it_vertex++)
38084  {
38085  local_tmp_vector_vertex_node[counter].resize(3);
38086  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
38087  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
38088  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
38089  counter++;
38090  }
38091 
38092  // ... same for the info. related with the target areas (turn
38093  // into vector)
38094  const unsigned ntarget_areas = sorted_target_areas.size();
38095  tmp_sorted_target_areas.resize(ntarget_areas);
38096  counter = 0;
38097  std::set<Vector<double>>::iterator it_area;
38098  for (it_area = sorted_target_areas.begin();
38099  it_area != sorted_target_areas.end();
38100  ++it_area)
38101  {
38102  tmp_sorted_target_areas[counter] = (*it_area)[1];
38103  ++counter;
38104  }
38105 
38106 #ifdef PARANOID
38107  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1))
38108  {
38109  std::ostringstream error_message;
38110  error_message
38111  << "The boundary (" << bound << ") was split during the "
38112  << "distribution process.\n"
38113  << "The problem is in the association of the target areas with "
38114  "the\n"
38115  << "elements that gave rise to the vertex coordinates.\n"
38116  << "The number of local nodes (" << nlocal_nodes
38117  << "), on the 'sub-polyline', is not\n"
38118  << "according with the number of target "
38119  << "areas (" << ntarget_areas << ")\nfor that number of nodes.\n"
38120  << "The target areas number MUST be equal to the number of\n"
38121  << "local nodes minus one\n\n";
38122  throw OomphLibError(error_message.str(),
38123  OOMPH_CURRENT_FUNCTION,
38124  OOMPH_EXCEPTION_LOCATION);
38125  }
38126 #endif
38127 
38128  // -------------------------------------------------------------------
38129  // Update the vertices along the boundary using the target area
38130  // to define the distance among them
38131  // -------------------------------------------------------------------
38132 
38133  // Tolerance below which the middle point can be deleted
38134  // (ratio of deflection to element length)
38135  double unrefinement_tolerance =
38136  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38137 
38138  // Apply unrefinement
38139  bool unrefinement_applied =
38140  unrefine_boundary_constrained_by_target_area(
38141  bound,
38142  chunk,
38143  local_tmp_vector_vertex_node,
38144  unrefinement_tolerance,
38145  tmp_sorted_target_areas);
38146 
38147  // Tolerance for refinement
38148  double refinement_tolerance =
38149  polygon_pt->polyline_pt(p)->refinement_tolerance();
38150 
38151  // Apply refinement
38152  bool refinement_applied = refine_boundary_constrained_by_target_area(
38153  mesh_geom_obj_pt,
38154  local_tmp_vector_vertex_node,
38155  refinement_tolerance,
38156  tmp_sorted_target_areas);
38157 
38158  // Clear the local containter to recover the nodes ordered using the
38159  // zeta value
38160  local_vertex_nodes.clear();
38161 
38162  // At the end of each unrefinement/refinement step store the new nodes
38163  // on the set that will give rise to the vertices of the new polyline
38164  // representation
38165  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
38166  for (unsigned i = 0; i < nnew_nodes; i++)
38167  {
38168  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
38169  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
38170  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
38171  vertex_nodes.insert(vertex_coord); // Global container
38172  local_vertex_nodes.insert(vertex_coord);
38173  }
38174 
38175  // Update the flag to indicate whether an unrefinement or
38176  // refinement was applied
38177  update_was_performed = (unrefinement_applied || refinement_applied);
38178 
38179 #ifdef OOMPH_HAS_MPI
38180  if (this->is_mesh_distributed())
38181  {
38182  // Add the set of vertices for the boundary, this will help to
38183  // detect if we need to deal with sub-boundaries
38184  sub_vertex_nodes.push_back(local_vertex_nodes);
38185  // Increase the counter for sub-boundaries
38186  nsub_boundaries++;
38187  }
38188 #endif
38189 
38190  } // while(nsorted_face_elements < nnon_halo_face_element)
38191 
38192  // Now turn into vector for ease of handling...
38193  unsigned npoly_vertex = vertex_nodes.size();
38194  // This will store all the vertices whether the boundary was split
38195  // or not
38196  tmp_vector_vertex_node.resize(npoly_vertex);
38197  unsigned count = 0;
38198  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
38199  it != vertex_nodes.end();
38200  ++it)
38201  {
38202  tmp_vector_vertex_node[count].resize(3);
38203  tmp_vector_vertex_node[count][0] = (*it)[0];
38204  tmp_vector_vertex_node[count][1] = (*it)[1];
38205  tmp_vector_vertex_node[count][2] = (*it)[2];
38206  ++count;
38207  }
38208 
38209 #ifdef OOMPH_HAS_MPI
38210  // --------- Stuff for the sub_boundaries ----- Begin section ---------
38211 #ifdef PARANOID
38212  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
38213  if (nsub_boundaries_set != nsub_boundaries)
38214  {
38215  std::ostringstream error_message;
38216  error_message
38217  << "The number of found sub-boundaries and the number of counted\n"
38218  << "sub-boundaries are different:\n"
38219  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
38220  << "Number of counted sub-boundaries: (" << nsub_boundaries << ")\n";
38221  throw OomphLibError(error_message.str(),
38222  OOMPH_CURRENT_FUNCTION,
38223  OOMPH_EXCEPTION_LOCATION);
38224  }
38225 #endif
38226 
38227  // Are there sub-boundaries (only appear in distributed meshes)
38228  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38229  {
38230  // Mark the boundary as been splitted in the partition process
38231  this->Boundary_was_splitted[bound] = true;
38232  // Resize the vector to store the info. of sub-boundaries
38233  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
38234  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38235  {
38236  // Turn info. into vector for ease of handling...
38237  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
38238  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
38239  unsigned subcount = 0;
38240  std::set<Vector<double>>::iterator subit;
38241  for (subit = sub_vertex_nodes[isub].begin();
38242  subit != sub_vertex_nodes[isub].end();
38243  ++subit)
38244  {
38245  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
38246  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
38247  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
38248  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
38249  ++subcount;
38250  }
38251  }
38252  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38253  // --------- Stuff for the sub_boundaries ----- End section ------------
38254 #endif // OOMPH_HAS_MPI
38255 
38256  // For further processing the three-dimensional vector has to be
38257  // reduced to a two-dimensional vector
38258  unsigned n_vertex = tmp_vector_vertex_node.size();
38259 
38260  // Resize the vector for vectices
38261  vector_vertex_node.resize(n_vertex);
38262  for (unsigned i = 0; i < n_vertex; i++)
38263  {
38264  vector_vertex_node[i].resize(2);
38265  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
38266  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
38267  }
38268 
38269 #ifdef OOMPH_HAS_MPI
38270  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38271  // Verify if need to deal with sub_boundaries
38272  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38273  {
38274  // For further processing the three-dimensional vector
38275  // has to be reduced to a two-dimensional vector
38276  // Resize the vector to store the info. of sub-boundaries
38277  sub_vector_vertex_node.resize(nsub_boundaries);
38278  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38279  {
38280  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
38281  // Resize the vector for vectices
38282  sub_vector_vertex_node[isub].resize(subn_vertex);
38283  for (unsigned i = 0; i < subn_vertex; i++)
38284  {
38285  sub_vector_vertex_node[isub][i].resize(2);
38286  sub_vector_vertex_node[isub][i][0] =
38287  sub_tmp_vector_vertex_node[isub][i][1];
38288  sub_vector_vertex_node[isub][i][1] =
38289  sub_tmp_vector_vertex_node[isub][i][2];
38290  }
38291  }
38292  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38293 
38294  // We already have the info. for the sub-boundaries (if necessary)
38295  // and then we can create the sub-boundaries representations to
38296  // ease the generation of the mesh by Triangle
38297 
38298  // --------- Stuff for the sub_boundaries ----- End section ------------
38299 #endif // OOMPH_HAS_MPI
38300 
38301  // --------------------------------------------------------------------
38302  // Check for contiguousness
38303  // --------------------------------------------------------------------
38304 #ifdef OOMPH_HAS_MPI
38305  // Only perform this checking if the mesh is not distributed. When
38306  // the mesh is distributed the polylines continuity is addressed
38307  // by the sort_polylines_helper() method
38308  if (!this->is_mesh_distributed())
38309 #endif
38310  {
38311  if (p > 0)
38312  {
38313  // Final end point of previous line
38314  Vector<double> final_vertex_of_previous_segment;
38315  unsigned n_prev_vertex =
38316  polygon_pt->curve_section_pt(p - 1)->nvertex();
38317  final_vertex_of_previous_segment =
38318  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
38319  1);
38320 
38321  unsigned prev_seg_boundary_id =
38322  polygon_pt->curve_section_pt(p - 1)->boundary_id();
38323 
38324  // Find the error between the final vertex of the previous
38325  // line and the first vertex of the current line
38326  double error = 0.0;
38327  for (unsigned i = 0; i < 2; i++)
38328  {
38329  const double dist = final_vertex_of_previous_segment[i] -
38330  (*vector_vertex_node.begin())[i];
38331  error += dist * dist;
38332  }
38333  error = sqrt(error);
38334 
38335  // If the error is bigger than the tolerance then
38336  // we probably need to reverse, but better check
38337  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38338  {
38339  // Find the error between the final vertex of the previous
38340  // line and the last vertex of the current line
38341  double rev_error = 0.0;
38342  for (unsigned i = 0; i < 2; i++)
38343  {
38344  const double dist = final_vertex_of_previous_segment[i] -
38345  (*--vector_vertex_node.end())[i];
38346  rev_error += dist * dist;
38347  }
38348  rev_error = sqrt(rev_error);
38349 
38350  if (rev_error >
38351  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38352  {
38353  // It could be possible that the first segment be reversed
38354  // and we did not notice it because this check does not
38355  // apply for the first segment. We can verify if the first
38356  // segment is reversed by using the vertex number 1
38357  if (p == 1)
38358  {
38359  // Initial end point of previous line
38360  Vector<double> initial_vertex_of_previous_segment;
38361 
38362  initial_vertex_of_previous_segment =
38363  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
38364 
38365  unsigned prev_seg_boundary_id =
38366  polygon_pt->curve_section_pt(p - 1)->boundary_id();
38367 
38368  // Find the error between the initial vertex of the previous
38369  // line and the first vertex of the current line
38370  double error = 0.0;
38371  for (unsigned i = 0; i < 2; i++)
38372  {
38373  const double dist = initial_vertex_of_previous_segment[i] -
38374  (*vector_vertex_node.begin())[i];
38375  error += dist * dist;
38376  }
38377  error = sqrt(error); // Reversed only the previous one
38378 
38379  // If the error is bigger than the tolerance then
38380  // we probably need to reverse, but better check
38381  if (error >
38382  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38383  {
38384  // Find the error between the final vertex of the previous
38385  // line and the last vertex of the current line
38386  double rev_error = 0.0;
38387  for (unsigned i = 0; i < 2; i++)
38388  {
38389  const double dist = initial_vertex_of_previous_segment[i] -
38390  (*--vector_vertex_node.end())[i];
38391  rev_error += dist * dist;
38392  }
38393  rev_error =
38394  sqrt(rev_error); // Reversed both the current one and
38395  // the previous one
38396 
38397  if (rev_error >
38398  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38399  {
38400  std::ostringstream error_stream;
38401  error_stream
38402  << "The distance between the first node of the current\n"
38403  << "line segment (boundary " << bound
38404  << ") and either end of "
38405  << "the previous line segment\n"
38406  << "(boundary " << prev_seg_boundary_id
38407  << ") is bigger than "
38408  << "the desired tolerance "
38409  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38410  << ".\n"
38411  << "This suggests that the polylines defining the "
38412  << "polygonal\n"
38413  << "representation are not properly ordered.\n"
38414  << "Fail on last vertex of polyline: ("
38415  << prev_seg_boundary_id << ") and\n"
38416  << "first vertex of polyline (" << bound << ").\n"
38417  << "This should have failed when first trying to "
38418  << "construct the\npolygon.\n";
38419  throw OomphLibError(error_stream.str(),
38420  OOMPH_CURRENT_FUNCTION,
38421  OOMPH_EXCEPTION_LOCATION);
38422  }
38423  else
38424  {
38425  // Reverse both
38426  // Reverse the current vector to line up with the
38427  // previous one
38428  std::reverse(vector_vertex_node.begin(),
38429  vector_vertex_node.end());
38430 
38431  polygon_pt->polyline_pt(p - 1)->reverse();
38432  }
38433  }
38434  else
38435  {
38436  // Reverse the previous one
38437  polygon_pt->polyline_pt(p - 1)->reverse();
38438  }
38439 
38440  } // if p == 1
38441  else
38442  {
38443  std::ostringstream error_stream;
38444  error_stream
38445  << "The distance between the first node of the current\n"
38446  << "line segment (boundary " << bound
38447  << ") and either end of "
38448  << "the previous line segment\n"
38449  << "(boundary " << prev_seg_boundary_id
38450  << ") is bigger than the "
38451  << "desired tolerance "
38452  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38453  << ".\n"
38454  << "This suggests that the polylines defining the polygonal\n"
38455  << "representation are not properly ordered.\n"
38456  << "Fail on last vertex of polyline: ("
38457  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
38458  << bound << ").\n"
38459  << "This should have failed when first trying to construct"
38460  << " the polygon.\n";
38461  throw OomphLibError(error_stream.str(),
38462  OOMPH_CURRENT_FUNCTION,
38463  OOMPH_EXCEPTION_LOCATION);
38464  }
38465  }
38466  else
38467  {
38468  // Reverse the current vector to line up with the previous one
38469  std::reverse(vector_vertex_node.begin(),
38470  vector_vertex_node.end());
38471  }
38472  } // error
38473 
38474  } // if ( p > 0 )
38475 
38476  } // if (!this->is_mesh_distributed())
38477 
38478  // --------------------------------------------------------------------
38479  // Update the polylines representation
38480  // --------------------------------------------------------------------
38481 
38482  // Always update the polylines representation, in a distributed
38483  // mesh it is necessary to update the polyline representation since
38484  // it may no longer have vertices (the boundary may not be part of
38485  // the domain in the current processor)
38486 
38487  // The new nunber of vertices
38488  n_vertex = vector_vertex_node.size();
38489 
38490  // Now update the polyline according to the new vertices
38491  TriangleMeshPolyLine* tmp_polyline_pt =
38492  new TriangleMeshPolyLine(vector_vertex_node, bound);
38493 
38494  // Create a temporal "curve section" version of the recently
38495  // created polyline
38496  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
38497 
38498  // Tolerance below which the middle point can be deleted (ratio of
38499  // deflection to element length)
38500  double unrefinement_tolerance =
38501  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38502 
38503  // Tolerance to add points
38504  double refinement_tolerance =
38505  polygon_pt->polyline_pt(p)->refinement_tolerance();
38506 
38507  // Establish refinement and unrefinement tolerance
38508  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38509  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38510 
38511  // Establish the maximum length constraint
38512  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38513  tmp_polyline_pt->set_maximum_length(maximum_length);
38514 
38515 #ifdef OOMPH_HAS_MPI
38516  // If the mesh is distributed check that the polyline still has
38517  // vertices
38518  if (this->is_mesh_distributed())
38519  {
38520  if (n_vertex >= 2)
38521  {
38522  // Pass the connection information from the old polyline to the
38523  // new one
38524  this->copy_connection_information(polygon_pt->polyline_pt(p),
38525  tmp_curve_section_pt);
38526  } // if (n_vertex >= 2)
38527  } // if (this->is_mesh_distributed())
38528  else
38529 #endif
38530  {
38531  // Pass the connection information from the old polyline to the
38532  // new one
38533  this->copy_connection_information(polygon_pt->polyline_pt(p),
38534  tmp_curve_section_pt);
38535  }
38536 
38537  // Now update the polyline according to the new vertices but first
38538  // check if the object is allowed to delete the representation or
38539  // if it should be done by other object
38540  bool delete_it_on_destructor = false;
38541 
38542  std::set<TriangleMeshCurveSection*>::iterator it =
38543  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38544 
38545  if (it != this->Free_curve_section_pt.end())
38546  {
38547  this->Free_curve_section_pt.erase(it);
38548  delete polygon_pt->curve_section_pt(p);
38549  delete_it_on_destructor = true;
38550  }
38551 
38552  // -------------------------------------------------------
38553  // Copying the new representation
38554  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38555 
38556  // Update the Boundary - Polyline map
38557  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38558 
38559  if (delete_it_on_destructor)
38560  {
38561  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38562  }
38563 
38564 #ifdef OOMPH_HAS_MPI
38565  // --------- Stuff for the sub_boundaries ----- Begin section --------
38566  // Verify if need to deal with sub_boundaries
38567  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38568  {
38569  // Create temporary representations for the boundaries, only to
38570  // create the mesh when calling Triangle
38571 
38572  // Clear all previous stored data
38573  this->Boundary_subpolylines[bound].clear();
38574 
38575  // Create storage for the sub-boundaries
38576  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38577  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38578  {
38579  // Update the polyline according to the sub set of vertices,
38580  TriangleMeshPolyLine* sub_tmp_polyline_pt =
38581  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38582 
38583  // Add the sub-polyline to the container to represent the
38584  // boundary in parts
38585  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38586 
38587  // No need to send the unrefinement/refinement and maximum
38588  // length constraints since these are only temporary
38589  // representations. These polylines can be deleted once the new
38590  // polygons that represent the distributed domain have been
38591  // created
38592 
38593  } // for (isub < nsub_boundaries)
38594 
38595  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38596  // --------- Stuff for the sub_boundaries ----- End section ---------
38597 #endif // OOMPH_HAS_MPI
38598 
38599  // Delete the allocated memory for the geometric object that
38600  // represents the boundary
38601  delete mesh_geom_obj_pt;
38602 
38603  } // for (p < n_polyline)
38604 
38605  // Cleanup the face mesh
38606  for (unsigned p = 0; p < n_polyline; p++)
38607  {
38608  face_mesh_pt[p]->flush_node_storage();
38609  delete face_mesh_pt[p];
38610  }
38611 
38612  return update_was_performed;
38613  }
38614 
38615  //======================================================================
38616  /// \short Updates the open curve but using the elements area instead
38617  /// of the default refinement and unrefinement methods
38618  //======================================================================
38619  template<class ELEMENT>
38621  TriangleMeshOpenCurve*& open_curve_pt, const Vector<double>& target_area)
38622  {
38623  // Verify if there was a change on the open curve representation
38624  unsigned update_was_performed = false;
38625 
38626  const unsigned nele = this->nelement();
38627 
38628  // - Get the vertices along the boundaries and for each element identify
38629  // its associated target error.
38630  // - Get face mesh representation of each polyline.
38631  // - Get the vertices with the help of face elements.
38632  // - Find the global index in the mesh of the face element
38633  // and use it to get its associated target area.
38634 
38635  // Get the face mesh representation
38636  Vector<Mesh*> face_mesh_pt;
38637  get_face_mesh_representation(open_curve_pt, face_mesh_pt);
38638 
38639  // Create vertices of the polylines by using the vertices of the
38640  // FaceElements
38641  Vector<double> vertex_coord(3); // zeta,x,y
38642  Vector<double> bound_left(1);
38643  Vector<double> bound_right(1);
38644 
38645  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38646 
38647  // Go for each curve section
38648  for (unsigned cs = 0; cs < ncurve_section; cs++)
38649  {
38650  // Get the MeshAsGeomObject representation just once per polyline,
38651  // this object is only used by the
38652  // refine_boundary_constrained_by_target_area() method. We get it
38653  // here to ensure that all processors (in a distributed context)
38654  // get this representation just once, and because an AllToAll MPI
38655  // communication is used in this calling
38656  MeshAsGeomObject* mesh_geom_obj_pt =
38657  new MeshAsGeomObject(face_mesh_pt[cs]);
38658 
38659  // Get the boundary id
38660  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
38661 
38662  // Get the chunk number
38663  const unsigned chunk =
38664  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38665 
38666  /// Use a vector of vector for vertices and target areas to deal
38667  /// with the cases when the boundaries are split by the
38668  /// distribution process. Internal boundaries may be completely or
38669  /// partially overlapped by shared boundaries
38670 
38671  // Loop over the face elements and add their vertices (they are
38672  // automatically sorted because of the set)
38673  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38674 
38675  // Store the non halo elements and the element at the other side of
38676  // the boundary (whatever it be halo or not), the first will be the
38677  // ones from which we will get the vertices (in even position)
38678  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38679 
38680  // Map to store the index of the face element on a boundary
38681  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
38682 
38683  // Map to know the already sorted face elements
38684  std::map<FiniteElement*, bool> face_element_done;
38685 
38686  for (unsigned ef = 0; ef < nface_element; ++ef)
38687  {
38688  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38689 
38690  // Skip the halo elements (not used as base elements, only
38691  // include those elements whose element at the other side of the
38692  // boundary is non halo)
38693 #ifdef OOMPH_HAS_MPI
38694  if (this->is_mesh_distributed())
38695  {
38696  // Only work with non-halo elements
38697  if (ele_face_pt->is_halo())
38698  {
38699  continue;
38700  }
38701  }
38702 #endif
38703 
38704  // Check if not already done
38705  if (!face_element_done[ele_face_pt])
38706  {
38707  // Add the element and look for the element at the other side
38708  // of the boundary to add it immediately after the new added
38709  // element
38710  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38711  // Create the map of the face element with the index
38712  face_element_index_on_boundary[ele_face_pt] = ef;
38713  // Mark the current element as done
38714  face_element_done[ele_face_pt] = true;
38715  // Get the number of nodes
38716  const unsigned nnodes = ele_face_pt->nnode();
38717  // Get the left and right node to look for the elements at the
38718  // other side of the boundary
38719  Node* left_node_pt = ele_face_pt->node_pt(0);
38720  Node* right_node_pt = ele_face_pt->node_pt(nnodes - 1);
38721 #ifdef PARANOID
38722  // Flag to know if the element at the other side of the
38723  // boundary was found
38724  bool found_other_side_face_ele = false;
38725 #endif
38726  for (unsigned iface = 0; iface < nface_element; iface++)
38727  {
38728  // Get the candidate face element
38729  FiniteElement* cele_face_pt =
38730  face_mesh_pt[cs]->finite_element_pt(iface);
38731  // Check if not already done
38732  if (!face_element_done[cele_face_pt])
38733  {
38734  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38735  Node* cright_node_pt = cele_face_pt->node_pt(nnodes - 1);
38736  // Check if the nodes are the same
38737  if ((left_node_pt == cleft_node_pt &&
38738  right_node_pt == cright_node_pt) ||
38739  (left_node_pt == cright_node_pt &&
38740  right_node_pt == cleft_node_pt))
38741  {
38742  // Add the element to the storage
38743  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38744  // ... and mark the element as done
38745  face_element_done[cele_face_pt] = true;
38746  // Create the map of the face element with the index
38747  face_element_index_on_boundary[cele_face_pt] = iface;
38748 #ifdef PARANOID
38749  // Set the flag of found other side face element
38750  found_other_side_face_ele = true;
38751 #endif
38752  break;
38753  }
38754  }
38755  } // (iface < nface_element)
38756 
38757 #ifdef PARANOID
38758  if (!found_other_side_face_ele)
38759  {
38760  std::ostringstream error_message;
38761  error_message
38762  << "The face element at the other side of the boundary (" << bound
38763  << ") was not found!!\n"
38764  << "These are the nodes of the face element:\n"
38765  << "(" << left_node_pt->x(0) << ", " << left_node_pt->x(1) << ") "
38766  << "and (" << right_node_pt->x(0) << "," << right_node_pt->x(1)
38767  << ")\n\n";
38768  throw OomphLibError(
38769  error_message.str(),
38770  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38771  OOMPH_EXCEPTION_LOCATION);
38772  }
38773 #endif
38774  } // if (!face_ele_done[ele_face_pt])
38775 
38776  } // (ef < nface_element)
38777 
38778  // Clear the map of the already done face elements
38779  // This will be used to help sorting the face elements
38780  face_element_done.clear();
38781 
38782  // Set of coordinates that are on the boundary
38783  // The entries are sorted on first entry in vector which stores
38784  // the boundary coordinate so the vertices come out in order!
38785  std::set<Vector<double>> vertex_nodes;
38786 
38787  // Vector to store the vertices, transfer the sorted vertices from the
38788  // set to this vector, --- including the z-value ---
38789  Vector<Vector<double>> tmp_vector_vertex_node;
38790 
38791  // Vector to store the coordinates of the polylines, same as the
38792  // tmp_vector_vertex_node vector (after adding more nodes) but
38793  // --- without the z-value ---, used to re-generate the polylines
38794  Vector<Vector<double>> vector_vertex_node;
38795 
38796 #ifdef OOMPH_HAS_MPI
38797  // Indicates if the set of vertices give rise to a internal
38798  // boundary that will be used as shared boundary or as normal
38799  // internal boundary -- Only used to deal with internal boundaries
38800  // in a distributed scheme
38801  std::vector<bool> internal_to_shared_boundary;
38802 
38803  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38804  // Set of coordinates that are on the boundary (splitted boundary version)
38805  // The first vector is used to allocate the points for each sub-boundary
38806  // Set entries are ordered on first entry in vector which stores
38807  // the boundary coordinate so the vertices come out in order!
38808  Vector<std::set<Vector<double>>> sub_vertex_nodes;
38809 
38810  // Vector to store the vertices, transfer the sorted vertices from the
38811  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38812  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
38813 
38814  // Vector to store the coordinates of the polylines that will represent
38815  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38816  // but --- without the z-value ---, used to generate the sub-polylines
38817  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
38818 
38819  // --------- Stuff to deal with splitted boundaries ----------- End ------
38820 
38821 #endif // #ifdef OOMPH_HAS_MPI
38822 
38823  // Sort the face element, those that have both elements (one at
38824  // each side of the boundary) marked as nonhalo, and those with one
38825  // nonhalo an the other as halo
38826 
38827  // Number of done face elements
38828  unsigned nsorted_face_elements = 0;
38829 
38830 #ifdef OOMPH_HAS_MPI
38831  // Counter for sub_boundaries
38832  unsigned nsub_boundaries = 0;
38833 #endif // #ifdef OOMPH_HAS_MPI
38834 
38835  // Total number of non halo double face element
38836  const unsigned nnon_halo_doubled_face_ele =
38837  non_halo_doubled_face_element_pt.size();
38838 
38839  // Continue until all the face elements have been sorted
38840  // This while is to deal with the cases of splitted boundaries
38841  while (nsorted_face_elements < nnon_halo_doubled_face_ele)
38842  {
38843  // Get and initial face element
38844  FiniteElement* ele_face_pt = 0;
38845  FiniteElement* repeated_ele_face_pt = 0;
38846 #ifdef PARANOID
38847  bool found_initial_face_element = false;
38848 #endif
38849 
38850  // Flag to know if we are working with a face element which the
38851  // face element at the other side of the boundary is also non
38852  // halo
38853  bool both_root_face_elements_are_nonhalo = false;
38854 
38855  unsigned iface = 0;
38856  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface += 2)
38857  {
38858  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38859  // If not done then take it as initial face element
38860  if (!face_element_done[ele_face_pt])
38861  {
38862  // Mark it as done
38863  face_element_done[ele_face_pt] = true;
38864  // Get the other side boundary face element
38865  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface + 1];
38866  // ... also mark as done the repeated face element
38867  face_element_done[repeated_ele_face_pt] = true;
38868 
38869 #ifdef OOMPH_HAS_MPI
38870  if (!repeated_ele_face_pt->is_halo())
38871  {
38872  both_root_face_elements_are_nonhalo = true;
38873  }
38874 #endif // #ifdef OOMPH_HAS_MPI
38875 
38876  // Plus two because internal boundaries have
38877  // two face elements per each edge
38878  nsorted_face_elements += 2;
38879  iface += 2;
38880 #ifdef PARANOID
38881  // And set the flag to true
38882  found_initial_face_element = true;
38883 #endif
38884  break;
38885  }
38886  }
38887 
38888 #ifdef PARANOID
38889  if (!found_initial_face_element)
38890  {
38891  std::ostringstream error_message;
38892  error_message << "Could not find an initial face element for the "
38893  "current segment\n";
38894  throw OomphLibError(error_message.str(),
38895  OOMPH_CURRENT_FUNCTION,
38896  OOMPH_EXCEPTION_LOCATION);
38897  }
38898 #endif
38899 
38900  // Local set of coordinates that are on the boundary Set entries
38901  // are ordered on first entry in vector which stores the boundary
38902  // coordinate so the vertices come out in order
38903  std::set<Vector<double>> local_vertex_nodes;
38904 
38905  // Vector to store the vertices, transfer the sorted vertices from the
38906  // set (local) to this vector (local), --- including the z-value ---
38907  Vector<Vector<double>> local_tmp_vector_vertex_node;
38908 
38909  // Vector to store the target areas, uses the same approach as the
38910  // set for the local_vertex_nodes, ordered on first entry
38911  std::set<Vector<double>> sorted_target_areas;
38912 
38913  // Vector to store the target areas, used to transfer the sorted target
38914  // areas from "sorted_target_areas" set
38915  Vector<double> tmp_sorted_target_areas;
38916 
38917  // ------------------------------------------------------------------
38918  // Add the vertices of the initial face element to the set of local
38919  // sorted vertices
38920  // ------------------------------------------------------------------
38921  const unsigned nnode = ele_face_pt->nnode();
38922  // Add the left-hand node to the set:
38923  // Boundary coordinate
38924  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
38925  vertex_coord[0] = bound_left[0];
38926 
38927  // Actual coordinates
38928  for (unsigned i = 0; i < 2; i++)
38929  {
38930  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
38931  }
38932  local_vertex_nodes.insert(vertex_coord);
38933 
38934  // Add the right-hand node to the set:
38935  // Boundary coordinate
38936  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
38937  bound, bound_right);
38938  vertex_coord[0] = bound_right[0];
38939 
38940  // Actual coordinates
38941  for (unsigned i = 0; i < 2; i++)
38942  {
38943  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
38944  }
38945  local_vertex_nodes.insert(vertex_coord);
38946 
38947  // The initial and final node on the set
38948  Node* first_node_pt = ele_face_pt->node_pt(0);
38949  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
38950 
38951  // -----------------------------------------------------
38952  // Find the global index in the mesh of the face element
38953  // and use it to get its associated target area
38954  // -----------------------------------------------------
38955  // Container to store the zeta value (used as index) and
38956  // the associated target area of the element
38957  Vector<double> zeta_target_area_values(2);
38958 
38959  // Use the minimum zeta value to sort the target areas
38960  // along the boundary
38961  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38962 
38963  // Get the index of the face element on the current boundary
38964  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38965  // Get the "ef"-th element on the boundary
38966  FiniteElement* el_pt = this->boundary_element_pt(bound, ef);
38967  double target_area_face_element = 0.0;
38968 
38969 #ifdef PARANOID
38970  bool found_global_element_index = false;
38971 #endif
38972  for (unsigned eg = 0; eg < nele; eg++)
38973  {
38974  // Get the "eg-th" element
38975  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
38976 
38977  // Compare with the element on the boundary, if equal then
38978  // store the target area
38979  if (el_pt == el_compare_pt)
38980  {
38981  target_area_face_element = target_area[eg];
38982 #ifdef PARANOID
38983  found_global_element_index = true;
38984 #endif
38985  break; // break the for (eg < nele) global element
38986  } // if el_pt == el_compare_pt
38987  } // for nele (on complete mesh)
38988 
38989 #ifdef PARANOID
38990  if (!found_global_element_index)
38991  {
38992  std::ostringstream error_message;
38993  error_message << "The global index for the (" << ef
38994  << ")-th face element "
38995  << "on\nthe (" << bound
38996  << ")-th boundary was not found!!!";
38997  throw OomphLibError(error_message.str(),
38998  OOMPH_CURRENT_FUNCTION,
38999  OOMPH_EXCEPTION_LOCATION);
39000  }
39001 #endif
39002 
39003  // Get the index of the repeated face element on the current boundary
39004  const unsigned ref =
39005  face_element_index_on_boundary[repeated_ele_face_pt];
39006  FiniteElement* rel_pt = this->boundary_element_pt(bound, ref);
39007  double target_area_repeated_face_element = 0.0;
39008 
39009 #ifdef PARANOID
39010  bool found_global_repeated_element_index = false;
39011 #endif
39012  for (unsigned eg = 0; eg < nele; eg++)
39013  {
39014  // Get the "eg-th" element
39015  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
39016 
39017  // Compare with the element on the boundary, if equal then
39018  // store the target area
39019  if (rel_pt == el_compare_pt)
39020  {
39021  target_area_repeated_face_element = target_area[eg];
39022 #ifdef PARANOID
39023  found_global_repeated_element_index = true;
39024 #endif
39025  break; // break the for (eg < nele) global element
39026  } // if rel_pt == el_compare_pt
39027  } // for nele (on complete mesh)
39028 
39029 #ifdef PARANOID
39030  if (!found_global_repeated_element_index)
39031  {
39032  std::ostringstream error_message;
39033  error_message << "The global index for the (" << ref
39034  << ")-th face element "
39035  << "on\nthe (" << bound
39036  << ")-th boundary was not found (repeated "
39037  << "face element)!!!";
39038  throw OomphLibError(error_message.str(),
39039  OOMPH_CURRENT_FUNCTION,
39040  OOMPH_EXCEPTION_LOCATION);
39041  }
39042 #endif
39043 
39044  // Choose the minimum target area from both elements, one at each side
39045  // of the edge on the boundary
39046  zeta_target_area_values[1] =
39047  std::min(target_area_face_element, target_area_repeated_face_element);
39048 
39049  // Add the target areas to the sorted set
39050  sorted_target_areas.insert(zeta_target_area_values);
39051  // ------------------------------------------------------------------
39052 
39053  // Continue iterating if a new face element has been added to the
39054  // list
39055  bool face_element_added = false;
39056 
39057  // While a new face element has been added to the set of sorted
39058  // face elements then re-iterate
39059  do
39060  {
39061  // Start from the next face elements since we have already
39062  // added the previous one as the initial face element (any
39063  // previous face element had to be added on previous
39064  // iterations)
39065  for (unsigned iiface = iface; iiface < nnon_halo_doubled_face_ele;
39066  iiface += 2)
39067  {
39068  face_element_added = false;
39069  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
39070 
39071  // Check that the face element with which we are working has
39072  // the same conditions as the root face element (both faces
39073  // are nonhalo or one face is halo and the other nonhalo)
39074 
39075  // Get the face element at the other side of the boundary
39076  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface + 1];
39077  bool both_face_elements_are_nonhalo = false;
39078 
39079 #ifdef OOMPH_HAS_MPI
39080  if (!repeated_ele_face_pt->is_halo())
39081  {
39082  both_face_elements_are_nonhalo = true;
39083  }
39084 #endif // #ifdef OOMPH_HAS_MPI
39085 
39086  if (!face_element_done[ele_face_pt] &&
39087  (both_face_elements_are_nonhalo ==
39088  both_root_face_elements_are_nonhalo))
39089  {
39090  // Get each individual node to check if they are contiguous
39091  const unsigned nlnode = ele_face_pt->nnode();
39092  Node* left_node_pt = ele_face_pt->node_pt(0);
39093  Node* right_node_pt = ele_face_pt->node_pt(nlnode - 1);
39094 
39095  if (left_node_pt == first_node_pt)
39096  {
39097  first_node_pt = right_node_pt;
39098  face_element_added = true;
39099  }
39100  else if (left_node_pt == last_node_pt)
39101  {
39102  last_node_pt = right_node_pt;
39103  face_element_added = true;
39104  }
39105  else if (right_node_pt == first_node_pt)
39106  {
39107  first_node_pt = left_node_pt;
39108  face_element_added = true;
39109  }
39110  else if (right_node_pt == last_node_pt)
39111  {
39112  last_node_pt = left_node_pt;
39113  face_element_added = true;
39114  }
39115 
39116  if (face_element_added)
39117  {
39118  // Add the left-hand node to the set:
39119  // Boundary coordinate
39120  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
39121  vertex_coord[0] = bound_left[0];
39122 
39123  // Actual coordinates
39124  for (unsigned i = 0; i < 2; i++)
39125  {
39126  vertex_coord[i + 1] = left_node_pt->x(i);
39127  }
39128  local_vertex_nodes.insert(vertex_coord);
39129 
39130  // Add the right-hand nodes to the set:
39131  // Boundary coordinate
39132  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
39133  vertex_coord[0] = bound_right[0];
39134 
39135  // Actual coordinates
39136  for (unsigned i = 0; i < 2; i++)
39137  {
39138  vertex_coord[i + 1] = right_node_pt->x(i);
39139  }
39140  local_vertex_nodes.insert(vertex_coord);
39141 
39142  // Mark as done only if one of its nodes has been
39143  // added to the list
39144  face_element_done[ele_face_pt] = true;
39145  // .. also mark as done the face element at the othe side of
39146  // the boundary
39147  repeated_ele_face_pt =
39148  non_halo_doubled_face_element_pt[iiface + 1];
39149  face_element_done[repeated_ele_face_pt] = true;
39150  // ... and increase the number of sorted face elements
39151  nsorted_face_elements += 2;
39152 
39153  // -----------------------------------------------------
39154  // Find the global index in the mesh of the face element
39155  // and use it to get its associated target area
39156  // -----------------------------------------------------
39157  // Use the minimum zeta value to sort the target areas
39158  // along the boundary
39159  zeta_target_area_values[0] =
39160  std::min(bound_left[0], bound_right[0]);
39161 
39162  // Get the "ef"-th element on the boundary
39163  const unsigned lef =
39164  face_element_index_on_boundary[ele_face_pt];
39165  FiniteElement* lel_pt = this->boundary_element_pt(bound, lef);
39166 
39167 #ifdef PARANOID
39168  found_global_element_index = false;
39169 #endif
39170  for (unsigned eg = 0; eg < nele; eg++)
39171  {
39172  // Get the "eg-th" element
39173  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
39174 
39175  // Compare with the element on the boundary, if equal then
39176  // store the target area
39177  if (lel_pt == lel_compare_pt)
39178  {
39179  target_area_face_element = target_area[eg];
39180 #ifdef PARANOID
39181  found_global_element_index = true;
39182 #endif
39183  break; // break the for (eg < nele) global element
39184  } // if lel_pt == lel_compare_pt
39185  } // for nele (on complete mesh)
39186 
39187 #ifdef PARANOID
39188  if (!found_global_element_index)
39189  {
39190  std::ostringstream error_message;
39191  error_message << "The global index for the (" << lef
39192  << ")-th face element "
39193  << "on\nthe (" << bound
39194  << ")-th boundary was not found!!!";
39195  throw OomphLibError(error_message.str(),
39196  OOMPH_CURRENT_FUNCTION,
39197  OOMPH_EXCEPTION_LOCATION);
39198  }
39199 #endif
39200 
39201  // Get the index of the repeated face element on the boundary
39202  const unsigned rlef =
39203  face_element_index_on_boundary[repeated_ele_face_pt];
39204  FiniteElement* rlel_pt = this->boundary_element_pt(bound, rlef);
39205 
39206 #ifdef PARANOID
39207  found_global_repeated_element_index = false;
39208 #endif
39209  for (unsigned eg = 0; eg < nele; eg++)
39210  {
39211  // Get the "eg-th" element
39212  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
39213 
39214  // Compare with the element on the boundary, if equal then
39215  // store the target area
39216  if (rlel_pt == lel_compare_pt)
39217  {
39218  target_area_repeated_face_element = target_area[eg];
39219 #ifdef PARANOID
39220  found_global_repeated_element_index = true;
39221 #endif
39222  break; // break the for (eg < nele) global element
39223  } // if rlel_pt == el_compare_pt
39224  } // for nele (on complete mesh)
39225 
39226 #ifdef PARANOID
39227  if (!found_global_repeated_element_index)
39228  {
39229  std::ostringstream error_message;
39230  error_message << "The global index for the (" << rlef
39231  << ")-th face element "
39232  << "on\nthe (" << bound
39233  << ")-th boundary was not found "
39234  << "(repeated face element)!!!";
39235  throw OomphLibError(error_message.str(),
39236  OOMPH_CURRENT_FUNCTION,
39237  OOMPH_EXCEPTION_LOCATION);
39238  }
39239 #endif
39240 
39241  // Choose the minimum target area from both elements, one
39242  // at each side of the edge on the boundary
39243  zeta_target_area_values[1] = std::min(
39244  target_area_face_element, target_area_repeated_face_element);
39245 
39246  // Add the target areas to the sorted set
39247  sorted_target_areas.insert(zeta_target_area_values);
39248 
39249  break;
39250  }
39251 
39252  } // if (!face_element_done[[ele_face_pt])
39253  } // for (iiface<nnon_halo_doubled_face_ele)
39254  } while (face_element_added &&
39255  (nsorted_face_elements < nnon_halo_doubled_face_ele));
39256 
39257  // -------------------------------------------------------------
39258  // At this point we already have a sorted set of nodes and can
39259  // be used to peform the unrefinement and refinement procedures
39260  // -------------------------------------------------------------
39261 
39262  // Get the number of nodes on the list
39263  const unsigned nlocal_nodes = local_vertex_nodes.size();
39264  // Change representation to vector for easy of handling ...
39265  local_tmp_vector_vertex_node.resize(nlocal_nodes);
39266 
39267  // Copy the vertices of the nodes
39268  unsigned counter = 0;
39269  std::set<Vector<double>>::iterator it_vertex;
39270  for (it_vertex = local_vertex_nodes.begin();
39271  it_vertex != local_vertex_nodes.end();
39272  it_vertex++)
39273  {
39274  local_tmp_vector_vertex_node[counter].resize(3);
39275  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39276  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39277  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39278  counter++;
39279  }
39280 
39281  // ... same for the info. related with the target areas (turn
39282  // into vector)
39283  const unsigned ntarget_areas = sorted_target_areas.size();
39284  tmp_sorted_target_areas.resize(ntarget_areas);
39285  counter = 0;
39286  std::set<Vector<double>>::iterator it_area;
39287  for (it_area = sorted_target_areas.begin();
39288  it_area != sorted_target_areas.end();
39289  ++it_area)
39290  {
39291  tmp_sorted_target_areas[counter] = (*it_area)[1];
39292  ++counter;
39293  }
39294 
39295 #ifdef PARANOID
39296  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1))
39297  {
39298  std::ostringstream error_message;
39299  error_message
39300  << "The boundary (" << bound << ") was split during the "
39301  << "distribution process.\n"
39302  << "The problem comes when associating the target areas with the "
39303  << "elements that gave\nrise to the vertex coordinates.\n"
39304  << "The number of local nodes on the 'sub-polyline' ("
39305  << nlocal_nodes << ") is not according with the number of target\n"
39306  << "areas (" << ntarget_areas << ") for that number of nodes.\n"
39307  << "The target areas number must be equal to the number of "
39308  "nodes-1\n";
39309  throw OomphLibError(error_message.str(),
39310  OOMPH_CURRENT_FUNCTION,
39311  OOMPH_EXCEPTION_LOCATION);
39312  }
39313 #endif
39314 
39315  // The unrefinement and refinement process needs to be applied
39316  // from the bottom-left node since the internal open curve could
39317  // lie on the shared boundaries
39318  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] <
39319  local_tmp_vector_vertex_node[0][2])
39320  {
39321  std::reverse(local_tmp_vector_vertex_node.begin(),
39322  local_tmp_vector_vertex_node.end());
39323  std::reverse(tmp_sorted_target_areas.begin(),
39324  tmp_sorted_target_areas.end());
39325  }
39326  else if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] ==
39327  local_tmp_vector_vertex_node[0][2])
39328  {
39329  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][1] <
39330  local_tmp_vector_vertex_node[0][1])
39331  {
39332  std::reverse(local_tmp_vector_vertex_node.begin(),
39333  local_tmp_vector_vertex_node.end());
39334  std::reverse(tmp_sorted_target_areas.begin(),
39335  tmp_sorted_target_areas.end());
39336  }
39337  }
39338 
39339  // ------------------------------------------------------------
39340  // Create the vertices along the boundary using the target
39341  // area to define the distance among them
39342  // ------------------------------------------------------------
39343 
39344  // Tolerance below which the middle point can be deleted
39345  // (ratio of deflection to element length)
39346  double unrefinement_tolerance =
39347  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39348 
39349  // Apply unrefinement
39350  bool unrefinement_applied =
39351  unrefine_boundary_constrained_by_target_area(
39352  bound,
39353  chunk,
39354  local_tmp_vector_vertex_node,
39355  unrefinement_tolerance,
39356  tmp_sorted_target_areas);
39357 
39358  // Tolerance for refinement
39359  double refinement_tolerance =
39360  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39361 
39362  // Apply refinement
39363  bool refinement_applied = refine_boundary_constrained_by_target_area(
39364  mesh_geom_obj_pt,
39365  local_tmp_vector_vertex_node,
39366  refinement_tolerance,
39367  tmp_sorted_target_areas);
39368 
39369  // Clear the local containter to recover the nodes ordered using
39370  // the zeta value
39371  local_vertex_nodes.clear();
39372 
39373  // At the end of each unrefinement/refinement step store the new
39374  // nodes on the set that will give rise to the vertices of the
39375  // new polyline representation
39376  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39377  for (unsigned i = 0; i < nnew_nodes; i++)
39378  {
39379  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39380  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39381  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39382  vertex_nodes.insert(vertex_coord); // Global container
39383  local_vertex_nodes.insert(vertex_coord);
39384  }
39385 
39386  // Update the flag to indicate whether an unrefinement or
39387  // refinement was applied
39388  update_was_performed = (unrefinement_applied || refinement_applied);
39389 
39390 #ifdef OOMPH_HAS_MPI
39391  if (this->is_mesh_distributed())
39392  {
39393  // Add the set of vertices for the boundary, this will help to
39394  // detect if we need to deal with sub_boundaries and
39395  // sub_polylines representations
39396  sub_vertex_nodes.push_back(local_vertex_nodes);
39397  // Increase the counter for sub_boundaries
39398  nsub_boundaries++;
39399 
39400  // Mark if the polyline created by these vertices will be used
39401  // as a shared boundary or as an internal boundary
39402  if (both_root_face_elements_are_nonhalo)
39403  {
39404  internal_to_shared_boundary.push_back(false);
39405  }
39406  else
39407  {
39408  internal_to_shared_boundary.push_back(true);
39409  }
39410  }
39411 #endif
39412 
39413  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39414  // This while is in charge of sorting all the face elements to
39415  // create the new representation of the polyline (also deals
39416  // with the sub-boundary cases)
39417 
39418  // Now turn into vector for ease of handling...
39419  const unsigned npoly_vertex = vertex_nodes.size();
39420  tmp_vector_vertex_node.resize(npoly_vertex);
39421  unsigned count = 0;
39422  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
39423  it != vertex_nodes.end();
39424  ++it)
39425  {
39426  tmp_vector_vertex_node[count].resize(3);
39427  tmp_vector_vertex_node[count][0] = (*it)[0];
39428  tmp_vector_vertex_node[count][1] = (*it)[1];
39429  tmp_vector_vertex_node[count][2] = (*it)[2];
39430  ++count;
39431  }
39432 
39433 #ifdef OOMPH_HAS_MPI
39434  // Check that the number of set of vertices marked to be part of a
39435  // shared boundary or of an internal boundaries be the same as the
39436  // total number of sub-boundaries
39437 #ifdef PARANOID
39438  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39439  const unsigned ninternal_to_shared_boundaries =
39440  internal_to_shared_boundary.size();
39441  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39442  {
39443  std::ostringstream error_message;
39444  error_message
39445  << "The number of found sub-boundaries and the number of marked "
39446  << "internal\nboundaries are different\n"
39447  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
39448  << "Number of marked internal boundaries: ("
39449  << ninternal_to_shared_boundaries << ")\n\n";
39450  throw OomphLibError(error_message.str(),
39451  OOMPH_CURRENT_FUNCTION,
39452  OOMPH_EXCEPTION_LOCATION);
39453  }
39454 #endif
39455 
39456  // --------- Stuff for the sub_boundaries ----- Begin section -------
39457 #ifdef PARANOID
39458  if (nsub_boundaries_set != nsub_boundaries)
39459  {
39460  std::ostringstream error_message;
39461  error_message
39462  << "The number of found sub-boundaries and the number of counted\n"
39463  << "sub-boundaries are different:\n"
39464  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
39465  << "Number of counted sub-boundaries: (" << nsub_boundaries
39466  << ")\n\n";
39467  throw OomphLibError(error_message.str(),
39468  OOMPH_CURRENT_FUNCTION,
39469  OOMPH_EXCEPTION_LOCATION);
39470  }
39471 #endif
39472 
39473  // Verify if need to deal with sub_boundaries
39474  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39475  {
39476  // Mark the boundary as been splitted in the partition process
39477  this->Boundary_was_splitted[bound] = true;
39478 
39479  // Resize the vector to store the info. of sub-boundaries
39480  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39481  // Loop over the sub-boundaries
39482  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39483  {
39484  // Turn info. into vector for ease of handling...
39485  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39486  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39487  unsigned subcount = 0;
39488  std::set<Vector<double>>::iterator subit;
39489  for (subit = sub_vertex_nodes[isub].begin();
39490  subit != sub_vertex_nodes[isub].end();
39491  ++subit)
39492  {
39493  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39494  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39495  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39496  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39497  ++subcount;
39498  }
39499  }
39500  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39501  // --------- Stuff for the sub_boundaries ----- End section ----------
39502 #endif // OOMPH_HAS_MPI
39503 
39504  // For further processing the three-dimensional vector has to be
39505  // reduced to a two-dimensional vector
39506  unsigned n_vertex = tmp_vector_vertex_node.size();
39507 
39508  // Resize the vector for vectices
39509  vector_vertex_node.resize(n_vertex);
39510  for (unsigned i = 0; i < n_vertex; i++)
39511  {
39512  vector_vertex_node[i].resize(2);
39513  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
39514  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
39515  }
39516 
39517 #ifdef OOMPH_HAS_MPI
39518  // --------- Stuff for the sub_boundaries ----- Begin section -------
39519  // Verify if need to deal with sub_boundaries
39520  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39521  {
39522  // For further processing the three-dimensional vector has to be
39523  // reduced to a two-dimensional vector
39524  // Resize the vector to store the info. of sub-boundaries
39525  sub_vector_vertex_node.resize(nsub_boundaries);
39526  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39527  {
39528  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
39529  // Resize the vector for vectices
39530  sub_vector_vertex_node[isub].resize(subn_vertex);
39531  for (unsigned i = 0; i < subn_vertex; i++)
39532  {
39533  sub_vector_vertex_node[isub][i].resize(2);
39534  sub_vector_vertex_node[isub][i][0] =
39535  sub_tmp_vector_vertex_node[isub][i][1];
39536  sub_vector_vertex_node[isub][i][1] =
39537  sub_tmp_vector_vertex_node[isub][i][2];
39538  }
39539  }
39540  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39541 
39542  // We already have the info. for the sub-boundaries (if necessary)
39543  // and then we can create the sub-boundaries representations to
39544  // ease the generation of the mesh by Triangle
39545 
39546  // --------- Stuff for the sub_boundaries ----- End section ---------
39547 #endif // OOMPH_HAS_MPI
39548 
39549  // ------------------------------------------------------------------
39550  // Check for contiguousness
39551  // ------------------------------------------------------------------
39552 #ifdef OOMPH_HAS_MPI
39553  // Only perform this checking if the mesh is not distributed When
39554  // the mesh is distributed the polylines continuity is addressed by
39555  // the sort_polylines_helper() method
39556  if (!this->is_mesh_distributed())
39557 #endif
39558  {
39559  if (cs > 0)
39560  {
39561  // Final end point of previous line
39562  Vector<double> final_vertex_of_previous_segment;
39563  unsigned n_prev_vertex =
39564  open_curve_pt->curve_section_pt(cs - 1)->nvertex();
39565  final_vertex_of_previous_segment =
39566  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(
39567  n_prev_vertex - 1);
39568 
39569  unsigned prev_seg_boundary_id =
39570  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
39571 
39572  // Find the error between the final vertex of the previous
39573  // line and the first vertex of the current line
39574  double error = 0.0;
39575  for (unsigned i = 0; i < 2; i++)
39576  {
39577  const double dist = final_vertex_of_previous_segment[i] -
39578  (*vector_vertex_node.begin())[i];
39579  error += dist * dist;
39580  }
39581  error = sqrt(error);
39582 
39583  // If the error is bigger than the tolerance then
39584  // we probably need to reverse, but better check
39585  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39586  {
39587  // Find the error between the final vertex of the previous
39588  // line and the last vertex of the current line
39589  double rev_error = 0.0;
39590  for (unsigned i = 0; i < 2; i++)
39591  {
39592  const double dist = final_vertex_of_previous_segment[i] -
39593  (*--vector_vertex_node.end())[i];
39594  rev_error += dist * dist;
39595  }
39596  rev_error = sqrt(rev_error);
39597 
39598  if (rev_error >
39599  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39600  {
39601  // It could be possible that the first segment be reversed and we
39602  // did not notice it because this check does not apply for the
39603  // first segment. We can verify if the first segment is reversed
39604  // by using the vertex number 1
39605  if (cs == 1)
39606  {
39607  // Initial end point of previous line
39608  Vector<double> initial_vertex_of_previous_segment;
39609 
39610  initial_vertex_of_previous_segment =
39611  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(0);
39612 
39613  unsigned prev_seg_boundary_id =
39614  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
39615 
39616  // Find the error between the initial vertex of the previous
39617  // line and the first vertex of the current line
39618  double error = 0.0;
39619  for (unsigned i = 0; i < 2; i++)
39620  {
39621  const double dist = initial_vertex_of_previous_segment[i] -
39622  (*vector_vertex_node.begin())[i];
39623  error += dist * dist;
39624  }
39625  error = sqrt(error); // Reversed only the previous one
39626 
39627  // If the error is bigger than the tolerance then
39628  // we probably need to reverse, but better check
39629  if (error >
39630  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39631  {
39632  // Find the error between the final vertex of the previous
39633  // line and the last vertex of the current line
39634  double rev_error = 0.0;
39635  for (unsigned i = 0; i < 2; i++)
39636  {
39637  const double dist = initial_vertex_of_previous_segment[i] -
39638  (*--vector_vertex_node.end())[i];
39639  rev_error += dist * dist;
39640  }
39641  rev_error = sqrt(rev_error); // Reversed both the current
39642  // one and the previous one
39643 
39644  if (rev_error >
39645  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39646  {
39647  std::ostringstream error_stream;
39648  error_stream
39649  << "The distance between the first node of the current\n"
39650  << "line segment (boundary " << bound
39651  << ") and either end of "
39652  << "the previous line segment\n"
39653  << "(boundary " << prev_seg_boundary_id
39654  << ") is bigger than"
39655  << " the desired tolerance "
39656  << ToleranceForVertexMismatchInPolygons::Tolerable_error
39657  << ".\n"
39658  << "This suggests that the polylines defining the "
39659  "polygonal\n"
39660  << "representation are not properly ordered.\n"
39661  << "Fail on last vertex of polyline: ("
39662  << prev_seg_boundary_id
39663  << ") and\nfirst vertex of polyline (" << bound
39664  << ").\nThis should have failed when first trying to "
39665  << "construct the\npolygon.\n";
39666  throw OomphLibError(error_stream.str(),
39667  OOMPH_CURRENT_FUNCTION,
39668  OOMPH_EXCEPTION_LOCATION);
39669  }
39670  else
39671  {
39672  // Reverse both
39673  // Reverse the current vector to line up with the previous
39674  // one
39675  std::reverse(vector_vertex_node.begin(),
39676  vector_vertex_node.end());
39677  open_curve_pt->polyline_pt(cs - 1)->reverse();
39678  }
39679  }
39680  else
39681  {
39682  // Reverse the previous one
39683  open_curve_pt->polyline_pt(cs - 1)->reverse();
39684  }
39685 
39686  } // if (cs == 1)
39687  else
39688  {
39689  std::ostringstream error_stream;
39690  error_stream
39691  << "The distance between the first node of the current\n"
39692  << "line segment (boundary " << bound
39693  << ") and either end of "
39694  << "the previous line segment\n"
39695  << "(boundary " << prev_seg_boundary_id
39696  << ") is bigger than the "
39697  << "desired tolerance "
39698  << ToleranceForVertexMismatchInPolygons::Tolerable_error
39699  << ".\n"
39700  << "This suggests that the polylines defining the polygonal\n"
39701  << "representation are not properly ordered.\n"
39702  << "Fail on last vertex of polyline: ("
39703  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
39704  << bound << ").\n"
39705  << "This should have failed when first trying to construct\n"
39706  << "the polygon.\n";
39707  throw OomphLibError(error_stream.str(),
39708  OOMPH_CURRENT_FUNCTION,
39709  OOMPH_EXCEPTION_LOCATION);
39710  }
39711  }
39712  else
39713  {
39714  // Reverse the current vector to line up with the previous one
39715  std::reverse(vector_vertex_node.begin(),
39716  vector_vertex_node.end());
39717  }
39718  }
39719 
39720  } // if (cs > 0)
39721 
39722  } // if (!this->is_mesh_distributed())
39723 
39724  // ---------------------------------------------------------------
39725  // Update the polylines representation
39726  // ---------------------------------------------------------------
39727  // Always update the polylines representation, in a distributed
39728  // mesh it is necessary to update the polyline representation since
39729  // it may no longer have vertices (the boundary may not be part of
39730  // the domain in the current processor)
39731 
39732  // The new number of vertices
39733  n_vertex = vector_vertex_node.size();
39734 
39735  // Update the polyline according to the new vertices
39736  TriangleMeshPolyLine* tmp_polyline_pt =
39737  new TriangleMeshPolyLine(vector_vertex_node, bound);
39738 
39739  // Create a temporal "curve section" version of the recently
39740  // created polyline
39741  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
39742 
39743  // Tolerance below which the middle point can be deleted (ratio of
39744  // deflection to element length)
39745  double unrefinement_tolerance =
39746  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39747 
39748  // Tolerance to add points
39749  double refinement_tolerance =
39750  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39751 
39752  // Establish refinement and unrefinement tolerance
39753  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39754  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39755 
39756  // Establish the maximum length constraint
39757  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39758  tmp_polyline_pt->set_maximum_length(maximum_length);
39759 
39760 #ifdef OOMPH_HAS_MPI
39761  // If the mesh is distributed check that the polyline still has
39762  // vertices
39763  if (this->is_mesh_distributed())
39764  {
39765  if (n_vertex >= 2)
39766  {
39767  // Pass the connection information from the old polyline to
39768  // the new one
39769  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39770  tmp_curve_section_pt);
39771  } // if (n_vertex >= 2)
39772  } // if (this->is_mesh_distributed())
39773  else
39774 #endif
39775  {
39776  // Pass the connection information from the old polyline to the
39777  // new one
39778  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39779  tmp_curve_section_pt);
39780  }
39781 
39782  // Now update the polyline according to the new vertices but first
39783  // check if the object is allowed to delete the representation or
39784  // if it should be done by other object
39785  bool delete_it_on_destructor = false;
39786 
39787  std::set<TriangleMeshCurveSection*>::iterator it =
39788  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39789 
39790  if (it != this->Free_curve_section_pt.end())
39791  {
39792  this->Free_curve_section_pt.erase(it);
39793  delete open_curve_pt->curve_section_pt(cs);
39794  delete_it_on_destructor = true;
39795  }
39796 
39797  // -------------------------------------------------------------
39798  // Copying the new representation
39799  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39800 
39801  // Update the Boundary - Polyline map
39802  this->Boundary_curve_section_pt[bound] =
39803  open_curve_pt->curve_section_pt(cs);
39804 
39805  if (delete_it_on_destructor)
39806  {
39807  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39808  }
39809 
39810 #ifdef OOMPH_HAS_MPI
39811  // If there are not sub-boundaries mark the boundary if need to be
39812  // trated as shared or as internal boundary
39813  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39814  {
39815  // Clear all previous stored data
39816  this->Boundary_marked_as_shared_boundary[bound].clear();
39817 
39818  // .. and store the flag for the boundary
39819  this->Boundary_marked_as_shared_boundary[bound].push_back(
39820  internal_to_shared_boundary[0]);
39821  }
39822  // --------- Stuff for the sub_boundaries ----- Begin section --------
39823  // Verify if need to deal with sub_boundaries
39824  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39825  {
39826  // Create temporary representations for the boundaries, only to
39827  // create the mesh when calling Triangle
39828 
39829  // Clear all previous stored data
39830  this->Boundary_subpolylines[bound].clear();
39831  // Now create storage for the sub-boundaries
39832  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39833 
39834  // Clear all previous stored data
39835  this->Boundary_marked_as_shared_boundary[bound].clear();
39836  // Create storage to mark the internal boundaries as shared
39837  // boundaries
39838  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39839  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39840  {
39841  // Now update the polyline according to the sub set of
39842  // vertices, set the chunk number of the polyline
39843  TriangleMeshPolyLine* sub_tmp_polyline_pt =
39844  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39845 
39846  // Add the sub-polyline to the container to represent the
39847  // boundary in parts
39848  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39849 
39850  // Copy the flag that mark the boundary as internal or as
39851  // shared bound
39852  this->Boundary_marked_as_shared_boundary[bound][isub] =
39853  internal_to_shared_boundary[isub];
39854 
39855  // No need to send the unrefinement/refinement and maximum
39856  // length constraints since these are only temporary
39857  // representations
39858 
39859  // But we certanly we need to pass the connection information
39860  // to the sub-polylines
39861  // Get a curve section representation of the sub-polyline
39862  TriangleMeshCurveSection* tmp_sub_curve_section_pt =
39863  sub_tmp_polyline_pt;
39864  this->copy_connection_information_to_sub_polylines(
39865  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39866 
39867  } // for (isub < nsub_boundaries)
39868 
39869  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39870  // --------- Stuff for the sub_boundaries ----- End section ---------
39871 #endif // OOMPH_HAS_MPI
39872 
39873  // Delete the allocated memory for the geometric object
39874  // that represents the curvilinear boundary
39875  delete mesh_geom_obj_pt;
39876 
39877  } // for (cs < ncurve_section)
39878 
39879  // Cleanup the face mesh
39880  for (unsigned p = 0; p < ncurve_section; p++)
39881  {
39882  face_mesh_pt[p]->flush_node_storage();
39883  delete face_mesh_pt[p];
39884  }
39885 
39886  return update_was_performed;
39887  }
39888 
39889 #ifdef OOMPH_HAS_MPI
39890  //======================================================================
39891  /// \short Updates the polylines using the elements area as
39892  /// constraint for the number of points along the boundaries
39893  //======================================================================
39894  template<class ELEMENT>
39896  Vector<TriangleMeshPolyLine*>& vector_polyline_pt,
39897  const Vector<double>& target_areas)
39898  {
39899  // Flag to check if there were a change on the shared boundary
39900  // representation
39901  unsigned update_was_performed = false;
39902 
39903  // Go through all the shared boundaries/polylines
39904  const unsigned n_polylines = vector_polyline_pt.size();
39905  for (unsigned pp = 0; pp < n_polylines; pp++)
39906  {
39907  // Get the boundary id of the current polyline
39908  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39909 
39910  // Get the chunk number
39911  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39912 
39913  // Get the face elements that created the shared boundary from the
39914  // bulk shared boundary elements
39915 
39916  // Compute the face elements from the shared boundary elements,
39917  // create an association from the face element with the "bulk"
39918  // elements
39919  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39920 
39921  // The temporary storage for the halo face elements
39922  Vector<FiniteElement*> halo_shared_face_ele_pt;
39923  // The temporary storage for the nonhalo face elements
39924  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39925 
39926  // Get the number of shared boundary elements associated with the
39927  // current shared boundary
39928  const unsigned nshared_bound_ele =
39929  this->nshared_boundary_element(shd_bnd_id);
39930 
39931  // Loop over the elements in the shared boundary to create the face
39932  // elements
39933  for (unsigned e = 0; e < nshared_bound_ele; e++)
39934  {
39935  // Get the shared boundary element
39936  FiniteElement* bulk_ele_pt =
39937  this->shared_boundary_element_pt(shd_bnd_id, e);
39938 
39939  // Get the face index
39940  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39941 
39942  // Before adding the new element we need to ensure that the edge
39943  // that this element represents has not been already added
39944  FiniteElement* face_ele_pt =
39945  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39946 
39947  // Establish the association between the bulk element and the
39948  // face element
39949  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39950 
39951  // Nonhalo element
39952  if (!bulk_ele_pt->is_halo())
39953  {
39954  // Add nonhalo shared face element to the container
39955  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39956  }
39957  else // halo element
39958  {
39959  // Add halo shared face element to the container
39960  halo_shared_face_ele_pt.push_back(face_ele_pt);
39961  }
39962 
39963  } // for (e < nshared_bound_ele)
39964 
39965  // Now we have the face elements, we need to ensure that the halo
39966  // and nonhalo bulk element are sorted one after the other
39967  Vector<Vector<FiniteElement*>> unsorted_shared_bulk_ele_pt;
39968 
39969  // Mark the face elements already used
39970  std::map<FiniteElement*, bool> shared_face_done;
39971 
39972  // Get the number of nonhalo face elements
39973  const unsigned nnonhalo_face_shared_ele =
39974  nonhalo_shared_face_ele_pt.size();
39975 
39976  // Get the number of halo face elements
39977  const unsigned nhalo_face_shared_ele = halo_shared_face_ele_pt.size();
39978 
39979 #ifdef PARANOID
39980  // The number of nonhalo shared face boundary elements must be the
39981  // half of the total number of shared boundary elements
39982  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39983  {
39984  std::ostringstream error_message;
39985  error_message
39986  << "The number of shared boundary elements (" << nshared_bound_ele
39987  << ") is not the double\nof the number of unsorted NONHALO shared "
39988  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39989  << "for the current boundary (" << shd_bnd_id << ")\n\n";
39990  throw OomphLibError(error_message.str(),
39991  OOMPH_CURRENT_FUNCTION,
39992  OOMPH_EXCEPTION_LOCATION);
39993  }
39994 
39995  // The number of halo shared face boundary elements must be the
39996  // half of the total number of shared boundary elements
39997  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39998  {
39999  std::ostringstream error_message;
40000  error_message
40001  << "The number of shared boundary elements (" << nshared_bound_ele
40002  << ") is not the double\nof the number of unsorted HALO shared "
40003  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
40004  << "for the current boundary (" << shd_bnd_id << ")\n\n";
40005  throw OomphLibError(error_message.str(),
40006  OOMPH_CURRENT_FUNCTION,
40007  OOMPH_EXCEPTION_LOCATION);
40008  }
40009 #endif
40010 
40011  // ------------------------------------------------------------------
40012  // Loop over the nonhalo face elements and look for the halo face
40013  // element at the other side of the shared boundary
40014  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40015  {
40016  // Get the inh-th face element
40017  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
40018 
40019  // Get the number of nodes on the face element
40020  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
40021  // Get the first and last node on the element
40022  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
40023  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh - 1);
40024 
40025  // Now find the (halo) face element at the other side of the
40026  // shared boundary
40027  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40028  {
40029  // Get the ih-th face element
40030  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
40031 
40032  // Check that the face element has not been done
40033  if (!shared_face_done[halo_face_ele_pt])
40034  {
40035  // Get the number of nodes on the face element
40036  const unsigned nnodes_h = halo_face_ele_pt->nnode();
40037  // Get the first and last node on the element
40038  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
40039  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h - 1);
40040 
40041  // If the nodes are the same then we have found the (halo)
40042  // face element at the other side of the shared boundary
40043  if (nh_first_node_pt == h_first_node_pt &&
40044  nh_last_node_pt == h_last_node_pt)
40045  {
40046  // Get the BULK elements associated with the face elements
40047  Vector<FiniteElement*> tmp_bulk_element_pt;
40048  // Get the BULK elements associated to the face elements
40049  // (the nonhalo and the halo)
40050  FiniteElement* nonhalo_bulk_ele_pt =
40051  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
40052  FiniteElement* halo_bulk_ele_pt =
40053  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
40054 
40055  // Add the BULK elements to the temporal storage
40056  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
40057  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
40058 
40059  // Store the pair of elements associated to the "edge"
40060  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
40061 
40062  // Mark the face elements as done
40063  shared_face_done[nonhalo_face_ele_pt] = true;
40064  shared_face_done[halo_face_ele_pt] = true;
40065 
40066  // Break the loop for (ih < nhalo_face_shared_ele)
40067  break;
40068  } // if (nh_first_node_pt == h_first_node_pt &&
40069  // nh_last_node_pt == h_last_node_pt)
40070  else if (nh_first_node_pt == h_last_node_pt &&
40071  nh_last_node_pt == h_first_node_pt)
40072  {
40073  // Get the BULK elements associated with the face elements
40074  Vector<FiniteElement*> tmp_bulk_element_pt;
40075  // Get the BULK elements associated to the face elements
40076  // (the nonhalo and the halo)
40077  FiniteElement* nonhalo_bulk_ele_pt =
40078  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
40079  FiniteElement* halo_bulk_ele_pt =
40080  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
40081 
40082  // Add the BULK elements to the temporal storage
40083  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
40084  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
40085 
40086  // Store the pair of elements associated to the "edge"
40087  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
40088 
40089  // Mark the face elements as done
40090  shared_face_done[nonhalo_face_ele_pt] = true;
40091  shared_face_done[halo_face_ele_pt] = true;
40092 
40093  // Break the loop for (ih < nhalo_face_shared_ele)
40094  break;
40095  } // else if (nh_first_node_pt == h_last_node_pt &&
40096  // nh_last_node_pt == h_first_node_pt)
40097 
40098  } // if (face_done[halo_face_ele_pt])
40099 
40100  } // for (ih < nhalo_face_shared_ele)
40101 
40102  } // for (inh < nnonhalo_face_shared_ele)
40103 
40104  // -------------------------------------------------------------
40105  // Now sort the face elements
40106  // -------------------------------------------------------------
40107 
40108  // We already have the shared face elements that make the shared
40109  // boundary (and the bulk elements), now sort them to create a
40110  // contiguous boundary
40111 
40112 #ifdef PARANOID
40113  const unsigned nunsorted_shared_bulk_ele =
40114  unsorted_shared_bulk_ele_pt.size();
40115 
40116  // The number of unsorted shared BULK elements MUST be the same
40117  // as the number of shared_boundary elements divided by two
40118  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
40119  {
40120  std::ostringstream error_message;
40121  error_message
40122  << "The number of shared boundary elements (" << nshared_bound_ele
40123  << ") is not the double\nof the number of unsorted shared bulk "
40124  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
40125  << "for the current boundary (" << shd_bnd_id << ")\n\n";
40126  throw OomphLibError(error_message.str(),
40127  OOMPH_CURRENT_FUNCTION,
40128  OOMPH_EXCEPTION_LOCATION);
40129  }
40130 
40131  // The number of done shared face elements MUST be the same as the
40132  // sum of the nonhalo and halo shared boundary face elements
40133  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
40134  shared_face_done.size())
40135  {
40136  std::ostringstream error_message;
40137  error_message << "The number of DONE shared boundary face elements ("
40138  << shared_face_done.size()
40139  << ") is not the same\n as the sum of"
40140  << "the nonhalo face shared boundary elements ("
40141  << nnonhalo_face_shared_ele
40142  << ")\nand the halo face shared "
40143  << "boundary elements (" << nhalo_face_shared_ele
40144  << ") for the\n/"
40145  << "current boundary (" << shd_bnd_id << ")\n\n";
40146  throw OomphLibError(error_message.str(),
40147  OOMPH_CURRENT_FUNCTION,
40148  OOMPH_EXCEPTION_LOCATION);
40149  }
40150 #endif
40151 
40152  // Clear the already done face elements
40153  shared_face_done.clear();
40154 
40155  // The number of sorted face elements
40156  unsigned nsorted_face_ele = 0;
40157 
40158  // Storing for the sorting nodes extracted from the face
40159  // elements. This are also used to update the polyline
40160  std::list<Node*> sorted_nodes;
40161 
40162  // Storing for the sorted shared face elements
40163  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
40164 
40165  // Get the root face element
40166  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
40167  nsorted_face_ele++;
40168 
40169  // Mark face as done
40170  shared_face_done[root_face_ele_pt] = true;
40171 
40172  // The initial and final node on the list
40173  const unsigned nnodes_root = root_face_ele_pt->nnode();
40174  Node* first_node_pt = root_face_ele_pt->node_pt(0);
40175  Node* last_node_pt = root_face_ele_pt->node_pt(nnodes_root - 1);
40176 
40177  // Push back on the list the new nodes
40178  sorted_nodes.push_back(first_node_pt);
40179  sorted_nodes.push_back(last_node_pt);
40180 
40181  // Store the bulk elements of the current face
40182  sorted_shared_bound_elements_pt.push_back(
40183  unsorted_shared_bulk_ele_pt[0][0]);
40184  sorted_shared_bound_elements_pt.push_back(
40185  unsorted_shared_bulk_ele_pt[0][1]);
40186 
40187  // Sort the face elements
40188  while (nsorted_face_ele < nnonhalo_face_shared_ele)
40189  {
40190  // Flag to indicate when a node was added
40191  bool node_added = false;
40192 
40193  // Start from the next edge since we have already added the
40194  // previous one as the initial face element
40195  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
40196  {
40197  FiniteElement* tmp_shared_face_ele_pt =
40198  nonhalo_shared_face_ele_pt[iface];
40199 
40200  // If face has not been sorted
40201  if (!shared_face_done[tmp_shared_face_ele_pt])
40202  {
40203  // Get the number of nodes for the current face element
40204  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
40205 
40206  // Get each individual node
40207  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
40208  Node* right_node_pt =
40209  tmp_shared_face_ele_pt->node_pt(tmp_nnodes - 1);
40210 
40211  if (left_node_pt == first_node_pt)
40212  {
40213  // Push front the new node
40214  sorted_nodes.push_front(right_node_pt);
40215  first_node_pt = right_node_pt;
40216  node_added = true;
40217 
40218  // Store the elements of the current face element
40219  sorted_shared_bound_elements_pt.push_front(
40220  unsorted_shared_bulk_ele_pt[iface][1]);
40221  sorted_shared_bound_elements_pt.push_front(
40222  unsorted_shared_bulk_ele_pt[iface][0]);
40223  }
40224  else if (left_node_pt == last_node_pt)
40225  {
40226  // Push back the new node
40227  sorted_nodes.push_back(right_node_pt);
40228  last_node_pt = right_node_pt;
40229  node_added = true;
40230 
40231  // Store the elements of the current face element
40232  sorted_shared_bound_elements_pt.push_back(
40233  unsorted_shared_bulk_ele_pt[iface][0]);
40234  sorted_shared_bound_elements_pt.push_back(
40235  unsorted_shared_bulk_ele_pt[iface][1]);
40236  }
40237  else if (right_node_pt == first_node_pt)
40238  {
40239  // Push front the new node
40240  sorted_nodes.push_front(left_node_pt);
40241  first_node_pt = left_node_pt;
40242  node_added = true;
40243 
40244  // Store the elements of the current face element
40245  sorted_shared_bound_elements_pt.push_front(
40246  unsorted_shared_bulk_ele_pt[iface][1]);
40247  sorted_shared_bound_elements_pt.push_front(
40248  unsorted_shared_bulk_ele_pt[iface][0]);
40249  }
40250  else if (right_node_pt == last_node_pt)
40251  {
40252  // Push back the new node
40253  sorted_nodes.push_back(left_node_pt);
40254  last_node_pt = left_node_pt;
40255  node_added = true;
40256 
40257  // Store the elements of the current face element
40258  sorted_shared_bound_elements_pt.push_back(
40259  unsorted_shared_bulk_ele_pt[iface][0]);
40260  sorted_shared_bound_elements_pt.push_back(
40261  unsorted_shared_bulk_ele_pt[iface][1]);
40262  }
40263 
40264  if (node_added)
40265  {
40266  // Mark as done if one of its nodes has been added to the
40267  // list
40268  shared_face_done[tmp_shared_face_ele_pt] = true;
40269  nsorted_face_ele++;
40270 
40271  // Break the for
40272  break;
40273  }
40274 
40275  } // if (!shared_face_done[tmp_shared_face_ele_pt])
40276 
40277  } // for (iface < nnonhalo_face_shared_ele)
40278 
40279  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
40280 
40281  // ----------------------------------------------------------------
40282  // Here we can safely delete the face elements, they are no longer
40283  // required
40284 
40285  // First the nonhalo face elements
40286  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40287  {
40288  delete nonhalo_shared_face_ele_pt[inh];
40289  nonhalo_shared_face_ele_pt[inh] = 0;
40290  } // for (inh < nnonhalo_face_shared_ele)
40291 
40292  // ... then the halo face elements
40293  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40294  {
40295  delete halo_shared_face_ele_pt[ih];
40296  halo_shared_face_ele_pt[ih] = 0;
40297  } // for (inh < nhalo_face_shared_ele)
40298 
40299  // ------------------------------------------------------------------
40300  // At this point we already have a sorted list of nodes, get the
40301  // vertices from them and store them in a vector container
40302 
40303  // Get the number of nodes on the list
40304  const unsigned n_nodes = sorted_nodes.size();
40305 
40306  // The vector to store the vertices
40307  Vector<Vector<double>> polyline_vertices(n_nodes);
40308 
40309  // Copy the vertices from the nodes
40310  unsigned counter = 0;
40311  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40312  it_nodes != sorted_nodes.end();
40313  it_nodes++)
40314  {
40315  polyline_vertices[counter].resize(2);
40316  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40317  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40318  counter++;
40319  }
40320 
40321  // ------------------------------------------------------------------
40322  // Now get the target areas associated to the shared boundary
40323  // elements
40324 
40325  // Copy the sorted elements in a vector
40326  Vector<FiniteElement*> sorted_shared_ele_pt;
40327  for (std::list<FiniteElement*>::iterator it_ele =
40328  sorted_shared_bound_elements_pt.begin();
40329  it_ele != sorted_shared_bound_elements_pt.end();
40330  it_ele++)
40331  {
40332  sorted_shared_ele_pt.push_back((*it_ele));
40333  }
40334 
40335  // Get the number of target areas
40336  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40337  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40338 
40339  // Mark those shared elements already found
40340  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40341 
40342  // Counter for the number of already done shared elements
40343  unsigned count_found_shared_element = 0;
40344 
40345  // Get the target area associated to the shared boundary elements
40346  const unsigned nele = this->nelement();
40347 
40348  // Loop over the elements to find the target areas associated to
40349  // the shared boundary elements
40350  for (unsigned e = 0; e < nele; e++)
40351  {
40352  GeneralisedElement* current_ele_pt = this->element_pt(e);
40353  // Now compare the current element with those in the sorted
40354  // shared element array
40355  for (unsigned s = 0; s < n_shared_target_areas; s++)
40356  {
40357  // Get the element
40358  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40359  // Create the pair element-index to check if done
40360  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40361  std::make_pair(current_shared_ele_pt, s);
40362  if (!shared_ele_done[pair_gen_ele_idx])
40363  {
40364  // Compare with the global element
40365  if (current_ele_pt == current_shared_ele_pt)
40366  {
40367  // Store the target area of the current shared element
40368  sorted_shared_target_areas[s] = target_areas[e];
40369  // Mark the shared element as done
40370  shared_ele_done[pair_gen_ele_idx] = true;
40371  // Increase the number of found elements
40372  count_found_shared_element++;
40373  } // if (current_ele_pt == current_shared_ele_pt)
40374  } // if (!shared_ele_done[current_shared_ele_pt])
40375  } // for (s < nshared_taget_areas)
40376 
40377  // Check if all shared elements have been found
40378  if (count_found_shared_element == n_shared_target_areas)
40379  {
40380  break;
40381  }
40382 
40383  } // for (e < nele)
40384 
40385 #ifdef PARANOID
40386  // Check if the number of found target areas is the same as the
40387  // number of shared target areas
40388  if (count_found_shared_element != n_shared_target_areas)
40389  {
40390  std::ostringstream error_message;
40391  error_message << "The number of found target areas ("
40392  << count_found_shared_element
40393  << ") is different from the "
40394  << "total number\nof target areas ("
40395  << n_shared_target_areas << ") in shared boundary ("
40396  << shd_bnd_id << ")\n\n";
40397  throw OomphLibError(error_message.str(),
40398  OOMPH_CURRENT_FUNCTION,
40399  OOMPH_EXCEPTION_LOCATION);
40400  }
40401 #endif
40402 
40403  // The number of vertices
40404  const unsigned n_vertices = n_nodes;
40405 
40406  // Get the number of segments from the input vector_polyline_pt
40407  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40408  // Get the number of segments from the input vector_polyline_pt to
40409  // ensure that the shared boundary corresponds to the one
40410  // represented by the shared face elements (this has sence when the
40411  // mesh was re-created from re-starting)
40412 
40413  // Check that the number of vertices correspond with the number of
40414  // segments
40415 #ifdef PARANOID
40416  if (n_segments != n_vertices - 1)
40417  {
40418  std::ostringstream error_message;
40419  error_message
40420  << "The number of segments from the current shared polyline "
40421  << "(" << n_segments << ") does not\ncorrespond with the number of "
40422  << "sorted vertices (" << n_vertices - 1
40423  << ") of the current shared\n"
40424  << "boundary\n\n";
40425  throw OomphLibError(error_message.str(),
40426  OOMPH_CURRENT_FUNCTION,
40427  OOMPH_EXCEPTION_LOCATION);
40428  }
40429 
40430  // Check that the number of target areas correspond with the number
40431  // of vertices
40432  if (n_segments != n_shared_target_areas / 2)
40433  {
40434  std::ostringstream error_message;
40435  error_message
40436  << "The number of segments for the current sorting of edges "
40437  << "(" << n_segments << ") is different\nfrom the number of "
40438  << "target areas (" << n_shared_target_areas / 2 << ")\n\n";
40439  throw OomphLibError(error_message.str(),
40440  OOMPH_CURRENT_FUNCTION,
40441  OOMPH_EXCEPTION_LOCATION);
40442  }
40443 #endif
40444 
40445  // ------------------------------------------------------------------
40446  // Get the target areas that are used to perform the unrefinement
40447  // and refinement operation. For each face element on a shared
40448  // polyline there are two bulk elements, a halo and a haloed
40449  // element, each with an associated target area. Review the
40450  // function
40451  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40452  // check how the shared boundaries were created
40453  Vector<double> polyline_target_area(n_segments);
40454  // Loop over the segments in the shared polyline
40455  for (unsigned s = 0; s < n_segments; s++)
40456  {
40457  // Get the minimum of the associated target areas
40458  polyline_target_area[s] =
40459  std::min(sorted_shared_target_areas[s * 2],
40460  sorted_shared_target_areas[(s * 2) + 1]);
40461  }
40462 
40463  // Before going to the unrefinement or refinement process check
40464  // that in all processors where the shared boundary lives start
40465  // from the same vertex.
40466  // Start from the bottom left vertex
40467  if (polyline_vertices[n_vertices - 1][1] < polyline_vertices[0][1])
40468  {
40469  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40470  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40471  }
40472  else if (polyline_vertices[n_vertices - 1][1] == polyline_vertices[0][1])
40473  {
40474  if (polyline_vertices[n_vertices - 1][0] < polyline_vertices[0][0])
40475  {
40476  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40477  std::reverse(polyline_target_area.begin(),
40478  polyline_target_area.end());
40479  }
40480  }
40481 
40482  // ------------------------------------------------------------------
40483  // Apply unrefinement
40484  bool unrefinement_applied = false;
40485  // Apply unefinement if there are more than three nodes at the
40486  // shared boundary
40487  if (n_vertices > 3)
40488  {
40489  unrefinement_applied =
40490  unrefine_shared_boundary_constrained_by_target_area(
40491  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40492  }
40493 
40494  // Apply refinement
40495  bool refinement_applied =
40496  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40497  polyline_target_area);
40498 
40499  // Was unrefinement/refinement applied
40500  update_was_performed |= (unrefinement_applied || refinement_applied);
40501 
40502  // ------------------------------------------------------------------
40503  // Update the polyline representation of the shared boundary
40504 
40505  // The new shared polyline representation
40506  TriangleMeshPolyLine* new_polyline_pt =
40507  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40508 
40509  // Get the curve section representation
40510  TriangleMeshCurveSection* curve_section_pt = vector_polyline_pt[pp];
40511 
40512  // Copy the connection information from the old shared polyline to
40513  // the new one
40514  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40515 
40516  // Now update the polyline according to the new vertices but first
40517  // check if the object is allowed to delete the representation or
40518  // if it should be done by other object
40519  bool delete_it_on_destructor = false;
40520 
40521  // Establish the element as being deleted by the destructor of the
40522  // class
40523  std::set<TriangleMeshCurveSection*>::iterator it =
40524  this->Free_curve_section_pt.find(curve_section_pt);
40525 
40526  if (it != this->Free_curve_section_pt.end())
40527  {
40528  this->Free_curve_section_pt.erase(it);
40529  delete curve_section_pt;
40530  delete_it_on_destructor = true;
40531  }
40532 
40533  // Copy the new representation to the output vector_polyline_pt
40534  vector_polyline_pt[pp] = new_polyline_pt;
40535 
40536  // Get the new curve section representation
40537  TriangleMeshCurveSection* new_curve_section_pt = vector_polyline_pt[pp];
40538 
40539  // Update the Boundary - Polyline map
40540  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40541 
40542  if (delete_it_on_destructor)
40543  {
40544  this->Free_curve_section_pt.insert(new_curve_section_pt);
40545  }
40546 
40547  } // for (pp < npoly)
40548 
40549  return update_was_performed;
40550  }
40551 #endif // #ifdef OOMPH_HAS_MPI
40552 
40553  //=========================================================================
40554  /// \short Helper function that performs the unrefinement process
40555  /// on the specified boundary by using the provided vertices
40556  /// representation and the associated target area.
40557  //=========================================================================
40558  template<class ELEMENT>
40561  const unsigned& b,
40562  const unsigned& c,
40563  Vector<Vector<double>>& vector_bnd_vertices,
40564  double& unrefinement_tolerance,
40565  Vector<double>& area_constraint)
40566  {
40567  // Store the vertices not allowed for deletion
40568  std::set<Vector<double>> no_delete_vertex;
40569 
40570  // Does the boundary receives connections?
40571  const bool boundary_receive_connections =
40572  this->boundary_connections(b, c, no_delete_vertex);
40573 
40574  // Boolean that indicates whether an actual update of the vertex
40575  // coordinates was performed
40576  bool unrefinement_applied = false;
40577 
40578  // Return inmedately
40579  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40580  {
40581  return unrefinement_applied;
40582  }
40583 
40584  // Strategy to delete nodes: Consider the target area of the
40585  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40586  // if the number of segments to be added is equal to zero for both
40587  // elements then compute the average of both target areas and check
40588  // if the number of segments is still zero, if that holds mark the
40589  // node to be deleted. Before delete the node check whether it is in
40590  // the non_delete_vertex list. Skip the i+1-th node and go for the
40591  // (i+2)-th one, it means, increase the counter for current node by
40592  // two.
40593 
40594  // Number of vertices on the boundary
40595  unsigned n_vertex = vector_bnd_vertices.size();
40596 
40597  // Compute a constant value
40598  const double constant_value = 4.0 / sqrt(3.0);
40599 
40600  if (n_vertex > 2)
40601  {
40602  // Go through all the vertices and delete points when the target area
40603  // indicates zero points along the boundary
40604  for (unsigned i = 1; i < n_vertex - 1; i += 2)
40605  {
40606  if (area_constraint[i - 1] > 0 && area_constraint[i] > 0)
40607  {
40608  const double local_zeta_first = vector_bnd_vertices[i - 1][0];
40609  const double local_zeta_last = vector_bnd_vertices[i + 1][0];
40610  const double local_length_zeta =
40611  std::fabs(local_zeta_last - local_zeta_first);
40612 
40613  const double x1 = vector_bnd_vertices[i - 1][1];
40614  const double y1 = vector_bnd_vertices[i - 1][2];
40615  const double x2 = vector_bnd_vertices[i + 1][1];
40616  const double y2 = vector_bnd_vertices[i + 1][2];
40617  const double local_length =
40618  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
40619 
40620  const double x_m = vector_bnd_vertices[i][1];
40621  const double y_m = vector_bnd_vertices[i][2];
40622 
40623  const double average_area_constraint =
40624  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
40625 
40626  // Compute the length of the the side of an equilateral
40627  // triangle
40628  const double length_side =
40629  sqrt(constant_value * average_area_constraint);
40630 
40631  const double length_side_zeta =
40632  (local_length_zeta * length_side) / local_length;
40633 
40634  // Is the new length greater that the old one
40635  if ((length_side_zeta / local_length_zeta) > 1.0)
40636  {
40637  // If the number of segments is zero then verify the condition for
40638  // deletion of nodes but using the condition in the default
40639  // unrefine_boundary() method. If both conditions are true then
40640  // delete the node
40641  // Maths from
40642  // http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40643  double a_x = vector_bnd_vertices[i - 1][1];
40644  double a_y = vector_bnd_vertices[i - 1][2];
40645  double b_x = vector_bnd_vertices[i][1];
40646  double b_y = vector_bnd_vertices[i][2];
40647  double c_x = vector_bnd_vertices[i + 1][1];
40648  double c_y = vector_bnd_vertices[i + 1][2];
40649 
40650  double a = b_x - a_x;
40651  double b = b_y - a_y;
40652  double c = c_x - a_x;
40653  double d = c_y - a_y;
40654 
40655  double e = a * (a_x + b_x) + b * (a_y + b_y);
40656  double f = c * (a_x + c_x) + d * (a_y + c_y);
40657 
40658  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
40659 
40660  bool do_it = false;
40661  if (std::fabs(g) < 1.0e-14)
40662  {
40663  do_it = true;
40664  }
40665  else
40666  {
40667  double p_x = (d * e - b * f) / g;
40668  double p_y = (a * f - c * e) / g;
40669 
40670  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
40671 
40672  double rhalfca_x = 0.5 * (a_x - c_x);
40673  double rhalfca_y = 0.5 * (a_y - c_y);
40674 
40675  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
40676 
40677  double sticky_out_bit =
40678  r - sqrt(std::fabs((r * r) - halfca_squared));
40679 
40680  // If sticky out bit divided by distance between end nodes
40681  // is less than tolerance the boundary is so flat that we
40682  // can safely kill the node
40683  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
40684  unrefinement_tolerance)
40685  {
40686  do_it = true;
40687  }
40688  }
40689 
40690  // If the vertex was proposed for deletion check if it is
40691  // allowed for being deleted
40692  if (do_it && boundary_receive_connections)
40693  {
40694  // Is the vertex one of the non deletable vertices
40695  for (std::set<Vector<double>>::iterator it =
40696  no_delete_vertex.begin();
40697  it != no_delete_vertex.end();
40698  it++)
40699  {
40700  // Compute the distance between the proposed node to
40701  // delete and the ones that should not be deleted
40702  const double x = (*it)[0];
40703  const double y = (*it)[1];
40704  double error = (x_m - x) * (x_m - x) + (y_m - y) * (y_m - y);
40705  error = sqrt(error);
40706 
40707  if (error <
40708  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40709  {
40710  // Do not delete the vertex
40711  do_it = false;
40712  break;
40713  }
40714  }
40715 
40716  } // if (do_it && boundary_receive_connections)
40717 
40718  // Remove node?
40719  if (do_it)
40720  {
40721  vector_bnd_vertices[i].resize(0);
40722  }
40723  } // if (n_seg == 0)
40724  } // if (area_constraint[i] >= 0)
40725  } // for (i < n_vertex-1)
40726 
40727  // Create a new (temporary) vector for the nodes, so that deleted nodes
40728  // are not stored
40729  Vector<Vector<double>> compact_vector;
40730 
40731  // Compact vector for target areas too
40732  Vector<double> compact_area_constraint;
40733 
40734  // Copy only the non deleted nodes
40735  for (unsigned i = 0; i < n_vertex; i++)
40736  {
40737  // If the entry was not deleted include it in the new vector
40738  if (vector_bnd_vertices[i].size() != 0)
40739  {
40740  compact_vector.push_back(vector_bnd_vertices[i]);
40741  }
40742  }
40743 
40744  // ------------------------------------------------------------------
40745  // Size of the target areas vector
40746  unsigned nsize_target = area_constraint.size();
40747  if (nsize_target == 1)
40748  {
40749  // No node was deleted, just copy the target area
40750  compact_area_constraint.push_back(area_constraint[0]);
40751  }
40752 
40753  // Copy the target areas
40754  for (unsigned i = 1; i < n_vertex; i += 2)
40755  {
40756  // If the entry was not deleted include the target areas of both
40757  // elements sharing the node
40758  if (vector_bnd_vertices[i].size() != 0)
40759  {
40760  compact_area_constraint.push_back(area_constraint[i - 1]);
40761  // To catch the case when working with even number of vertex
40762  if (i < nsize_target)
40763  {
40764  compact_area_constraint.push_back(area_constraint[i]);
40765  }
40766  }
40767  else
40768  {
40769  // If the node was deleted then compute the new target area as the
40770  // average of the target area of the elements sharing the node
40771  double new_area_constraint =
40772  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
40773  compact_area_constraint.push_back(new_area_constraint);
40774  }
40775  }
40776 
40777  // If the size of the compact vector is different from the size of the
40778  // vector before applying the area length constraint then the polyline
40779  // was updated
40780  if (n_vertex != compact_vector.size())
40781  {
40782  unrefinement_applied = true;
40783  }
40784 
40785  // Copy back to the original vector
40786  n_vertex = compact_vector.size();
40787  vector_bnd_vertices.resize(n_vertex);
40788  for (unsigned i = 0; i < n_vertex; i++)
40789  {
40790  vector_bnd_vertices[i].resize(3);
40791  vector_bnd_vertices[i][0] = compact_vector[i][0];
40792  vector_bnd_vertices[i][1] = compact_vector[i][1];
40793  vector_bnd_vertices[i][2] = compact_vector[i][2];
40794  }
40795 
40796  // Copy back to the original vector of target areas
40797  unsigned ntarget_areas = compact_area_constraint.size();
40798  area_constraint.resize(ntarget_areas);
40799  for (unsigned i = 0; i < ntarget_areas; i++)
40800  {
40801  area_constraint[i] = compact_area_constraint[i];
40802  }
40803 
40804  } // if (n_vertex > 2)
40805 
40806  return unrefinement_applied;
40807  }
40808 
40809  //=========================================================================
40810  /// \short Helper function that performs the refinement process
40811  /// on the specified boundary by using the provided vertices
40812  /// representation and the associated elements target area.
40813  //=========================================================================
40814  template<class ELEMENT>
40817  MeshAsGeomObject* mesh_geom_obj_pt,
40818  Vector<Vector<double>>& vector_bnd_vertices,
40819  double& refinement_tolerance,
40820  Vector<double>& area_constraint)
40821  {
40822  // Boolean that indicates whether an actual update of the vertex
40823  // coordinates was performed
40824  bool refinement_applied = false;
40825 
40826  // Return inmedately
40827  if (!Do_boundary_refinement_constrained_by_target_areas)
40828  {
40829  return refinement_applied;
40830  }
40831 
40832  // Get the total number of current vertices
40833  unsigned n_vertex = vector_bnd_vertices.size();
40834 
40835  // Compute a constant value
40836  const double constant_value = 4.0 / sqrt(3.0);
40837 
40838  if (n_vertex > 1)
40839  {
40840  // Create a new (temporary) vector for the nodes, so that new
40841  // nodes can be stored
40842  Vector<Vector<double>> new_vector;
40843 
40844  // Go through all the vertices and create points according to the
40845  // specified element area
40846  for (unsigned i = 0; i < n_vertex - 1; i++)
40847  {
40848  // Include the first node
40849  new_vector.push_back(vector_bnd_vertices[i]);
40850 
40851  if (area_constraint[i] > 0)
40852  {
40853  double local_zeta_first = vector_bnd_vertices[i][0];
40854  double local_zeta_last = vector_bnd_vertices[i + 1][0];
40855  const double local_length_zeta =
40856  std::fabs(local_zeta_last - local_zeta_first);
40857 
40858  // Check if need to interchange the zeta first and the zeta
40859  // last (to ensure the same order in zeta values in any two
40860  // processors)
40861  if (local_zeta_first > local_zeta_last)
40862  {
40863  const double tmp_zeta = local_zeta_first;
40864  local_zeta_first = local_zeta_last;
40865  local_zeta_last = tmp_zeta;
40866  }
40867 
40868  const double x1 = vector_bnd_vertices[i][1];
40869  const double y1 = vector_bnd_vertices[i][2];
40870  const double x2 = vector_bnd_vertices[i + 1][1];
40871  const double y2 = vector_bnd_vertices[i + 1][2];
40872  const double local_length =
40873  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
40874 
40875  // Compute the length in zeta units
40876  const double length_side = sqrt(constant_value * area_constraint[i]);
40877  const double length_side_zeta =
40878  (local_length_zeta * length_side) / local_length;
40879 
40880  // How many segments should be introduced
40881  const double n_seg_double = length_side_zeta / local_length_zeta;
40882 
40883  // One segment initialy (the original one)
40884  unsigned n_seg = 1;
40885 
40886  // How many more segments to introduce?
40887  n_seg += static_cast<unsigned>(std::floor(1.0 / n_seg_double));
40888 
40889  // Are there segments to introduce? There must be at least one
40890  // segment, the original one
40891  if (n_seg > 0)
40892  {
40893  // The zeta increment
40894  double zeta_increment = (local_length_zeta) / ((double)n_seg);
40895 
40896  Vector<double> zeta(1);
40897  // Create the n_seg segmets between each pair of nodes
40898  for (unsigned s = 1; s < n_seg; s++)
40899  {
40900  // Get the coordinates
40901  zeta[0] = local_zeta_first + zeta_increment * double(s);
40902  Vector<double> vertex(2);
40903  mesh_geom_obj_pt->position(zeta, vertex);
40904 
40905  // Create the new node
40906  Vector<double> new_node(3);
40907  new_node[0] = zeta[0];
40908  new_node[1] = vertex[0];
40909  new_node[2] = vertex[1];
40910 
40911  // Include the new node
40912  new_vector.push_back(new_node);
40913 
40914  } // for (s<=n_seg)
40915 
40916  } // if (n_seg > 0)
40917 
40918  } // if (area_constraint[i] >= 0)
40919 
40920  } // for (i < n_vertex-1)
40921 
40922  // Once finished all the vertices add the last node to the vector
40923  new_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
40924 
40925  // If the new size of the vector (including the added nodes) is
40926  // different from the size of the vector before applying the
40927  // area length constraint then the polyline was updated
40928  n_vertex = new_vector.size();
40929  if (n_vertex != vector_bnd_vertices.size())
40930  {
40931  refinement_applied = true;
40932  }
40933 
40934  // Copy the new representation
40935  vector_bnd_vertices.resize(n_vertex);
40936  for (unsigned i = 0; i < n_vertex; i++)
40937  {
40938  vector_bnd_vertices[i].resize(3);
40939  vector_bnd_vertices[i][0] = new_vector[i][0];
40940  vector_bnd_vertices[i][1] = new_vector[i][1];
40941  vector_bnd_vertices[i][2] = new_vector[i][2];
40942  }
40943 
40944  } // if (n_vertex > 1)
40945 
40946  return refinement_applied;
40947  }
40948 
40949  //======================================================================
40950  /// \short Helper function that performs the unrefinement process
40951  /// on the specified boundary by using the provided vertices
40952  /// representation and the associated target area.
40953  /// NOTE: This is the version that applies unrefinement to shared
40954  /// boundaries
40955  //======================================================================
40956  template<class ELEMENT>
40959  const unsigned& b,
40960  const unsigned& c,
40961  Vector<Vector<double>>& vector_bnd_vertices,
40962  Vector<double>& area_constraint)
40963  {
40964  // Store the vertices not allowed for deletion
40965  std::set<Vector<double>> no_delete_vertex;
40966 
40967  // Does the boundary receives connections?
40968  const bool boundary_receive_connections =
40969  this->boundary_connections(b, c, no_delete_vertex);
40970 
40971  // Boolean that indicates whether an actual update of the vertex
40972  // coordinates was performed
40973  bool unrefinement_applied = false;
40974 
40975  // Return inmedately
40976  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40977  {
40978  return unrefinement_applied;
40979  }
40980 
40981  // Strategy to delete nodes:
40982 
40983  // Strategy to delete nodes: Consider the target area of the
40984  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40985  // if the number of segments to be added is equal to zero for both
40986  // elements then compute the average of both target areas and check
40987  // if the number of segments is still zero, if that holds mark the
40988  // node to be deleted. Before delete the node check whether it is in
40989  // the non_delete_vertex list. Skip the i+1-th node and go for the
40990  // (i+2)-th one, it means, increase the counter for current node by
40991  // two.
40992 
40993  // Number of vertices on the boundary
40994  unsigned n_vertex = vector_bnd_vertices.size();
40995 
40996  // Compute a constant value
40997  const double constant_value = 4.0 / sqrt(3.0);
40998 
40999  if (n_vertex > 2)
41000  {
41001  // Go through all the vertices and delete points when the target
41002  // area indicates zero points along the boundary
41003  for (unsigned i = 1; i < n_vertex - 1; i += 2)
41004  {
41005  // Is a target area assigned to the left and right element of
41006  // the i-th node
41007  if (area_constraint[i - 1] > 0 && area_constraint[i] > 0)
41008  {
41009  // Get the vertices to the left
41010  const double x1 = vector_bnd_vertices[i - 1][0];
41011  const double y1 = vector_bnd_vertices[i - 1][1];
41012  // ... and to the right of the i-th vertex
41013  const double x2 = vector_bnd_vertices[i + 1][0];
41014  const double y2 = vector_bnd_vertices[i + 1][1];
41015 
41016  // The distance
41017  const double local_length =
41018  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
41019 
41020  // Get the middle vertex
41021  const double x_m = vector_bnd_vertices[i][0];
41022  const double y_m = vector_bnd_vertices[i][1];
41023 
41024  // The average area
41025  const double average_area_constraint =
41026  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
41027 
41028  // Compute the base length of the triangle with
41029  // area_constraint area
41030  const double length_side =
41031  sqrt(constant_value * average_area_constraint);
41032 
41033  // Is the new length greater than the old one
41034  if ((length_side / local_length) > 1.0)
41035  {
41036  bool do_it = true;
41037 
41038  // If the vertex was proposed for deletion check that it is
41039  // allowed for being deleted
41040  if (do_it && boundary_receive_connections)
41041  {
41042  // Is the vertex one of the non deletable vertices
41043  for (std::set<Vector<double>>::iterator it =
41044  no_delete_vertex.begin();
41045  it != no_delete_vertex.end();
41046  it++)
41047  {
41048  // Compute the distance between the proposed node to delete
41049  // and the ones that should not be deleted
41050  const double x = (*it)[0];
41051  const double y = (*it)[1];
41052  double error = (x_m - x) * (x_m - x) + (y_m - y) * (y_m - y);
41053  error = sqrt(error);
41054 
41055  if (error <
41056  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41057  {
41058  // Do not delete the vertex
41059  do_it = false;
41060  break;
41061  }
41062  }
41063 
41064  } // if (do_it && boundary_receive_connections)
41065 
41066  // Remove node?
41067  if (do_it)
41068  {
41069  vector_bnd_vertices[i].resize(0);
41070  }
41071  } // if ((local_length / length_side) <= 1.3)
41072 
41073  } // if (area_constraint[i] >= 0)
41074 
41075  } // for (i < n_vertex-1)
41076 
41077  // Create a new (temporary) vector for the nodes, so that deleted nodes
41078  // are not stored
41079  Vector<Vector<double>> compact_vector;
41080 
41081  // Compact vector for target areas too
41082  Vector<double> compact_area_constraint;
41083 
41084  // Copy only the non deleted nodes
41085  for (unsigned i = 0; i < n_vertex; i++)
41086  {
41087  // If the entry was not deleted include it in the new vector
41088  if (vector_bnd_vertices[i].size() != 0)
41089  {
41090  compact_vector.push_back(vector_bnd_vertices[i]);
41091  }
41092  }
41093 
41094  // ------------------------------------------------------------------
41095  // The number of target areas
41096  unsigned n_area_constraint = area_constraint.size();
41097  if (n_area_constraint == 1)
41098  {
41099  // No node could be deleted then just copy the target area
41100  compact_area_constraint.push_back(area_constraint[0]);
41101  }
41102 
41103  // Copy the target areas
41104  for (unsigned i = 1; i < n_vertex; i += 2)
41105  {
41106  // If the entry was not deleted include the target areas of both
41107  // elements sharing the node
41108  if (vector_bnd_vertices[i].size() != 0)
41109  {
41110  compact_area_constraint.push_back(area_constraint[i - 1]);
41111  // To catch the case when working with even number of vertices
41112  if (i < n_area_constraint)
41113  {
41114  compact_area_constraint.push_back(area_constraint[i]);
41115  }
41116  }
41117  else
41118  {
41119  // If the node was deleted then compute the new target area as the
41120  // average of the target area of the elements sharing the node
41121  const double new_area_constraint =
41122  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
41123  compact_area_constraint.push_back(new_area_constraint);
41124  }
41125  } // for (i < n_vertex)
41126 
41127  // If the size of the compact vector is different from the size of
41128  // the vector before applying the area length constraint then the
41129  // polyline was updated
41130  if (n_vertex != compact_vector.size())
41131  {
41132  unrefinement_applied = true;
41133  }
41134 
41135  // Copy back to the original vector
41136  n_vertex = compact_vector.size();
41137  vector_bnd_vertices.resize(n_vertex);
41138  for (unsigned i = 0; i < n_vertex; i++)
41139  {
41140  vector_bnd_vertices[i].resize(2);
41141  vector_bnd_vertices[i][0] = compact_vector[i][0];
41142  vector_bnd_vertices[i][1] = compact_vector[i][1];
41143  }
41144 
41145  // Copy back to the original vector of target areas
41146  unsigned ntarget_areas = compact_area_constraint.size();
41147  area_constraint.resize(ntarget_areas);
41148  for (unsigned i = 0; i < ntarget_areas; i++)
41149  {
41150  area_constraint[i] = compact_area_constraint[i];
41151  }
41152 
41153  } // if (n_vertex > 2)
41154 
41155  return unrefinement_applied;
41156  }
41157 
41158  //======================================================================
41159  /// \short Helper function that performs the refinement process
41160  /// on the specified boundary by using the provided vertices
41161  /// representation and the associated elements target area.
41162  /// NOTE: This is the version that applies refinement to shared
41163  /// boundaries
41164  //======================================================================
41165  template<class ELEMENT>
41168  Vector<Vector<double>>& vector_bnd_vertices,
41169  Vector<double>& area_constraint)
41170  {
41171  // Boolean that indicates whether an actual update of the vertex
41172  // coordinates was performed
41173  bool refinement_applied = false;
41174 
41175  // Return inmedately
41176  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
41177  {
41178  return refinement_applied;
41179  }
41180 
41181  // Get the number of segments
41182  unsigned nsegments = vector_bnd_vertices.size() - 1;
41183 
41184  // Create a new (temporary) vector for the nodes, so that new nodes
41185  // can be stored
41186  Vector<Vector<double>> tmp_bnd_vertices;
41187 
41188  // Compute a constant value
41189  const double constant_value = 4.0 / sqrt(3.0);
41190 
41191  for (unsigned s = 0; s < nsegments; s++)
41192  {
41193  Vector<double> left_vertex = vector_bnd_vertices[s];
41194  Vector<double> right_vertex = vector_bnd_vertices[s + 1];
41195 
41196  // Initial and final point of the segment
41197  const double x1 = left_vertex[0];
41198  const double y1 = left_vertex[1];
41199  const double x2 = right_vertex[0];
41200  const double y2 = right_vertex[1];
41201 
41202  // Lenght of the segment
41203  const double segment_length =
41204  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
41205 
41206  // Compute the distance for the new segments
41207  const double new_segment_length =
41208  sqrt(constant_value * area_constraint[s]);
41209 
41210  // How many segments should be introduced
41211  const double n_seg_double = new_segment_length / segment_length;
41212 
41213  // One segment initialy (the original one)
41214  unsigned nseg = 1;
41215  // How many more segments to introduce?
41216  nseg += static_cast<unsigned>(std::floor(1.0 / n_seg_double));
41217 
41218  // The left vertex must be always included, even though no new vertex
41219  // be added
41220  tmp_bnd_vertices.push_back(left_vertex);
41221 
41222  // Are there segments to introduce? There must be at least one
41223  // segment, the original one
41224  if (nseg > 0)
41225  {
41226  // Create intermediate vertices
41227  double incrementx = (right_vertex[0] - left_vertex[0]) / (double)(nseg);
41228  double incrementy = (right_vertex[1] - left_vertex[1]) / (double)(nseg);
41229  for (unsigned i = 1; i < nseg; i++)
41230  {
41231  Vector<double> tmp_vertex(2);
41232  tmp_vertex[0] = left_vertex[0] + incrementx * i;
41233  tmp_vertex[1] = left_vertex[1] + incrementy * i;
41234  tmp_bnd_vertices.push_back(tmp_vertex);
41235  } // for (i < nseg)
41236 
41237  } // if (nseg > 0)
41238 
41239  } // for (s < nsegments)
41240 
41241  // Add the last vertex
41242  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
41243 
41244  // If the new size of the vector (including the added nodes) is
41245  // different from the size of the vector before applying the
41246  // refinement then the polyline was updated
41247  nsegments = tmp_bnd_vertices.size() - 1;
41248  if (nsegments != vector_bnd_vertices.size() - 1)
41249  {
41250  refinement_applied = true;
41251 
41252  // Copy across
41253  vector_bnd_vertices.resize(nsegments + 1);
41254  for (unsigned i = 0; i < nsegments + 1; i++)
41255  {
41256  vector_bnd_vertices[i].resize(2);
41257  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
41258  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
41259  }
41260  }
41261 
41262  return refinement_applied;
41263  }
41264 
41265  //======================================================================
41266  /// \short Updates the polylines representation after restart
41267  //======================================================================
41268  template<class ELEMENT>
41270  TriangleMeshPolygon*& polygon_pt)
41271  {
41272  // **********************************************************************
41273  // 1) Collect the elements adjacet to the polyline boundary id and
41274  // update the polyline
41275  // **********************************************************************
41276 
41277  // (1.1) Get the face mesh representation
41278  Vector<Mesh*> face_mesh_pt;
41279  get_face_mesh_representation(polygon_pt, face_mesh_pt);
41280 
41281  // (1.2) Create vertices of the polylines by using the vertices of the
41282  // FaceElements
41283  Vector<double> vertex_coord(3); // zeta,x,y
41284  Vector<double> bound_left(1);
41285  Vector<double> bound_right(1);
41286 
41287  const unsigned n_polyline = polygon_pt->npolyline();
41288 
41289  // Go for each polyline
41290  for (unsigned p = 0; p < n_polyline; p++)
41291  {
41292  // Get the MeshAsGeomObject representation just once per polyline,
41293  // this object is only used by the
41294  // refine_boundary_constrained_by_target_area() method. We get it here
41295  // to ensure that all processors (in a distributed context) get this
41296  // representation just once, and because an AllToAll MPI communication
41297  // is used in this calling
41298  MeshAsGeomObject* mesh_geom_obj_pt =
41299  new MeshAsGeomObject(face_mesh_pt[p]);
41300 
41301  // Set of coordinates that are on the boundary
41302  // Set entries are ordered on first entry in vector which stores
41303  // the boundary coordinate so the vertices come out in order!
41304  std::set<Vector<double>> vertex_nodes;
41305 
41306  // Vector to store the vertices, transfer the sorted vertices from the
41307  // set to this vector, --- including the z-value ---
41308  Vector<Vector<double>> tmp_vector_vertex_node;
41309 
41310  // Vector to store the coordinates of the polylines, same as the
41311  // tmp_vector_vertex_node vector (after adding more nodes) but
41312  // --- without the z-value ---, used to re-generate the polylines
41313  Vector<Vector<double>> vector_vertex_node;
41314 
41315 #ifdef OOMPH_HAS_MPI
41316  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41317  // Set of coordinates that are on the boundary (splitted boundary version)
41318  // The first vector is used to allocate the points for each sub-boundary
41319  // Set entries are ordered on first entry in vector which stores
41320  // the boundary coordinate so the vertices come out in order!
41321  Vector<std::set<Vector<double>>> sub_vertex_nodes;
41322 
41323  // Vector to store the vertices, transfer the sorted vertices from the
41324  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41325  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
41326 
41327  // Vector to store the coordinates of the polylines that will represent
41328  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41329  // but --- without the z-value ---, used to generate the sub-polylines
41330  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
41331  // --------- Stuff to deal with splitted boundaries ----------- End ------
41332 #endif
41333 
41334  // Get the boundary id
41335  unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
41336 
41337  /// Use a vector of vector for vertices and target areas to
41338  /// deal with the cases when the boundaries are split by the
41339  /// distribution process
41340 
41341  // Loop over the face elements (ordered) and add their vertices
41342  const unsigned nface_element = face_mesh_pt[p]->nelement();
41343 
41344  // Store the non halo face elements, the ones from which we will
41345  // get the vertices
41346  Vector<FiniteElement*> non_halo_face_element_pt;
41347  // Map to store the index of the face element on a boundary
41348  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
41349 
41350  for (unsigned ef = 0; ef < nface_element; ++ef)
41351  {
41352  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41353  // Skip the halo elements
41354 #ifdef OOMPH_HAS_MPI
41355  if (this->is_mesh_distributed())
41356  {
41357  // Only work with non-halo elements
41358  if (ele_face_pt->is_halo())
41359  {
41360  continue;
41361  }
41362  }
41363 #endif
41364  // Add the face element to the vector
41365  non_halo_face_element_pt.push_back(ele_face_pt);
41366  face_element_index_on_boundary[ele_face_pt] = ef;
41367  }
41368 
41369  // Get the number of non halo face element
41370  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41371 
41372  // Map to know the already sorted face elements
41373  std::map<FiniteElement*, bool> face_element_done;
41374 
41375  // Number of done face elements
41376  unsigned nsorted_face_elements = 0;
41377 
41378 #ifdef OOMPH_HAS_MPI
41379  // Counter for sub_boundaries
41380  unsigned nsub_boundaries = 0;
41381 #endif // #ifdef OOMPH_HAS_MPI
41382 
41383  // Continue until all the face elements have been sorted
41384  // This while is to deal with the cases of splitted boundaries
41385  while (nsorted_face_elements < nnon_halo_face_element)
41386  {
41387  // Get and initial face element
41388  FiniteElement* ele_face_pt = 0;
41389 #ifdef PARANOID
41390  bool found_initial_face_element = false;
41391 #endif
41392 
41393  unsigned iface = 0;
41394  for (iface = 0; iface < nnon_halo_face_element; iface++)
41395  {
41396  ele_face_pt = non_halo_face_element_pt[iface];
41397  // If not done then take it as initial face element
41398  if (!face_element_done[ele_face_pt])
41399  {
41400 #ifdef PARANOID
41401  found_initial_face_element = true;
41402 #endif
41403  nsorted_face_elements++;
41404  iface++;
41405  break;
41406  }
41407  }
41408 
41409 #ifdef PARANOID
41410  if (!found_initial_face_element)
41411  {
41412  std::ostringstream error_message;
41413  error_message << "Could not find an initial face element for the "
41414  "current segment\n";
41415  // << "----- Possible memory leak -----\n";
41416  throw OomphLibError(
41417  error_message.str(),
41418  "RefineableTriangleMesh::update_polygon_after_restart()",
41419  OOMPH_EXCEPTION_LOCATION);
41420  }
41421 #endif
41422 
41423  // Local set of coordinates that are on the boundary
41424  // Set entries are ordered on first entry in vector which stores
41425  // the boundary coordinate so the vertices come out in order!
41426  std::set<Vector<double>> local_vertex_nodes;
41427 
41428  // Vector to store the vertices, transfer the sorted vertices from the
41429  // set (local) to this vector (local), --- including the z-value ---
41430  Vector<Vector<double>> local_tmp_vector_vertex_node;
41431 
41432  // ------------------------------------------------------------------
41433  // ------------------------------------------------------------------
41434  // -----------------------------------------------------------------
41435  // Add the vertices of the initial face element to the set of local
41436  // sorted vertices
41437  // -----------------------------------------------------------------
41438  unsigned nnode = ele_face_pt->nnode();
41439  // Add the left-hand node to the set:
41440  // Boundary coordinate
41441  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
41442  vertex_coord[0] = bound_left[0];
41443 
41444  // Actual coordinates
41445  for (unsigned i = 0; i < 2; i++)
41446  {
41447  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
41448  }
41449  local_vertex_nodes.insert(vertex_coord);
41450 
41451  // Add the right-hand nodes to the set:
41452  // Boundary coordinate
41453  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
41454  bound, bound_right);
41455  vertex_coord[0] = bound_right[0];
41456 
41457  // Actual coordinates
41458  for (unsigned i = 0; i < 2; i++)
41459  {
41460  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
41461  }
41462  local_vertex_nodes.insert(vertex_coord);
41463 
41464  // The initial and final node on the set
41465  Node* first_node_pt = ele_face_pt->node_pt(0);
41466  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
41467 
41468  // Mark the current face element as done
41469  face_element_done[ele_face_pt] = true;
41470 
41471  // ------------------------------------------------------------------
41472  // ------------------------------------------------------------------
41473  // ------------------------------------------------------------------
41474 
41475  // Continue iterating if a new face element has been added to the
41476  // list
41477  bool face_element_added = false;
41478 
41479  // While a new face element has been added to the set of sorted
41480  // face elements then re-iterate
41481  do
41482  {
41483  // Start from the next face elements since we have already added
41484  // the previous one as the initial face element (any previous face
41485  // element had to be added on previous iterations)
41486  for (unsigned iiface = iface; iiface < nnon_halo_face_element;
41487  iiface++)
41488  {
41489  face_element_added = false;
41490  ele_face_pt = non_halo_face_element_pt[iiface];
41491  if (!face_element_done[ele_face_pt])
41492  {
41493  // Get each individual node to check if they are contiguous
41494  nnode = ele_face_pt->nnode();
41495  Node* left_node_pt = ele_face_pt->node_pt(0);
41496  Node* right_node_pt = ele_face_pt->node_pt(nnode - 1);
41497 
41498  if (left_node_pt == first_node_pt)
41499  {
41500  first_node_pt = right_node_pt;
41501  face_element_added = true;
41502  }
41503  else if (left_node_pt == last_node_pt)
41504  {
41505  last_node_pt = right_node_pt;
41506  face_element_added = true;
41507  }
41508  else if (right_node_pt == first_node_pt)
41509  {
41510  first_node_pt = left_node_pt;
41511  face_element_added = true;
41512  }
41513  else if (right_node_pt == last_node_pt)
41514  {
41515  last_node_pt = left_node_pt;
41516  face_element_added = true;
41517  }
41518 
41519  if (face_element_added)
41520  {
41521  // Add the left-hand node to the set:
41522  // Boundary coordinate
41523  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
41524  vertex_coord[0] = bound_left[0];
41525 
41526  // Actual coordinates
41527  for (unsigned i = 0; i < 2; i++)
41528  {
41529  vertex_coord[i + 1] = left_node_pt->x(i);
41530  }
41531  local_vertex_nodes.insert(vertex_coord);
41532 
41533  // Add the right-hand nodes to the set:
41534  // Boundary coordinate
41535  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
41536  vertex_coord[0] = bound_right[0];
41537 
41538  // Actual coordinates
41539  for (unsigned i = 0; i < 2; i++)
41540  {
41541  vertex_coord[i + 1] = right_node_pt->x(i);
41542  }
41543  local_vertex_nodes.insert(vertex_coord);
41544 
41545  // Mark as done only if one of its nodes has been
41546  // added to the list
41547  face_element_done[ele_face_pt] = true;
41548  nsorted_face_elements++;
41549 
41550  break;
41551  }
41552 
41553  } // if (!edge_done[edge])
41554  } // for (iiedge < nedges)
41555  } while (face_element_added &&
41556  (nsorted_face_elements < nnon_halo_face_element));
41557 
41558  // -----------------------------------------------------------------
41559  // At this point we already have a sorted set of nodes and
41560  // can be used to peform the unrefinement and refinement procedures
41561  // -----------------------------------------------------------------
41562 
41563  // Get the number of nodes on the list
41564  const unsigned nlocal_nodes = local_vertex_nodes.size();
41565  // Change representation to vector for easy of handling ...
41566  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41567 
41568  // Copy the vertices of the nodes
41569  unsigned counter = 0;
41570  std::set<Vector<double>>::iterator it_vertex;
41571  for (it_vertex = local_vertex_nodes.begin();
41572  it_vertex != local_vertex_nodes.end();
41573  it_vertex++)
41574  {
41575  local_tmp_vector_vertex_node[counter].resize(3);
41576  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41577  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41578  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41579  counter++;
41580  }
41581 
41582  // *********************************************************************
41583  // 3) Create the vertices along the boundary using the target area to
41584  // define the distance among them
41585  // *********************************************************************
41586 
41587  // Clear the local containter to recover the nodes ordered using the
41588  // zeta value
41589  local_vertex_nodes.clear();
41590 
41591  // At the end of each unrefinement/refinement step store the new nodes
41592  // on the set that will give rise to the vertices of the new polyline
41593  // representation
41594  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41595  for (unsigned i = 0; i < nnew_nodes; i++)
41596  {
41597  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41598  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41599  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41600  vertex_nodes.insert(vertex_coord); // Global container
41601  local_vertex_nodes.insert(vertex_coord);
41602  }
41603 
41604 #ifdef OOMPH_HAS_MPI
41605  if (this->is_mesh_distributed())
41606  {
41607  // Add the set of vertices for the boundary, this will help to detect
41608  // if we need to deal with sub_boundaries and sub_polylines represen.
41609  sub_vertex_nodes.push_back(local_vertex_nodes);
41610  // Increase the counter for sub_boundaries
41611  nsub_boundaries++;
41612  }
41613 #endif
41614 
41615  } // while(nsorted_face_elements < nnon_halo_face_element)
41616 
41617  // Now turn into vector for ease of handling...
41618  unsigned npoly_vertex = vertex_nodes.size();
41619  tmp_vector_vertex_node.resize(npoly_vertex);
41620  unsigned count = 0;
41621  std::set<Vector<double>>::iterator it;
41622  for (it = vertex_nodes.begin(); it != vertex_nodes.end(); ++it)
41623  {
41624  tmp_vector_vertex_node[count].resize(3);
41625  tmp_vector_vertex_node[count][0] = (*it)[0];
41626  tmp_vector_vertex_node[count][1] = (*it)[1];
41627  tmp_vector_vertex_node[count][2] = (*it)[2];
41628  ++count;
41629  }
41630 
41631 #ifdef OOMPH_HAS_MPI
41632  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41633 #ifdef PARANOID
41634  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41635  if (nsub_boundaries_set != nsub_boundaries)
41636  {
41637  std::ostringstream error_message;
41638  error_message
41639  << "The number of found sub-boundaries and the number of counted\n"
41640  << "sub-boundaries are different:\n"
41641  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
41642  << "Number of counted sub-boundaries: (" << nsub_boundaries << ")\n";
41643  throw OomphLibError(
41644  error_message.str(),
41645  "RefineableTriangleMesh::update_polygon_after_restart()",
41646  OOMPH_EXCEPTION_LOCATION);
41647  }
41648 #endif
41649 
41650  // Verify if need to deal with sub_boundaries
41651  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41652  {
41653  // Mark the boundary as been splitted in the partition process
41654  this->Boundary_was_splitted[bound] = true;
41655  // Resize the vector to store the info. of sub-boundaries
41656  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41657  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41658  {
41659  // Turn info. into vector for ease of handling...
41660  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41661  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41662  unsigned subcount = 0;
41663  std::set<Vector<double>>::iterator subit;
41664  for (subit = sub_vertex_nodes[isub].begin();
41665  subit != sub_vertex_nodes[isub].end();
41666  ++subit)
41667  {
41668  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41669  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41670  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41671  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41672  ++subcount;
41673  }
41674  }
41675  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41676  // --------- Stuff for the sub_boundaries ----- End section ------------
41677 #endif // OOMPH_HAS_MPI
41678 
41679 
41680  // For further processing the three-dimensional vector
41681  // has to be reduced to a two-dimensional vector
41682  unsigned n_vertex = tmp_vector_vertex_node.size();
41683 
41684  // Resize the vector for vectices
41685  vector_vertex_node.resize(n_vertex);
41686  for (unsigned i = 0; i < n_vertex; i++)
41687  {
41688  vector_vertex_node[i].resize(2);
41689  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
41690  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
41691  }
41692 
41693 #ifdef OOMPH_HAS_MPI
41694  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41695  // Verify if need to deal with sub_boundaries
41696  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41697  {
41698  // For further processing the three-dimensional vector
41699  // has to be reduced to a two-dimensional vector
41700  // Resize the vector to store the info. of sub-boundaries
41701  sub_vector_vertex_node.resize(nsub_boundaries);
41702  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41703  {
41704  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
41705  // Resize the vector for vectices
41706  sub_vector_vertex_node[isub].resize(subn_vertex);
41707  for (unsigned i = 0; i < subn_vertex; i++)
41708  {
41709  sub_vector_vertex_node[isub][i].resize(2);
41710  sub_vector_vertex_node[isub][i][0] =
41711  sub_tmp_vector_vertex_node[isub][i][1];
41712  sub_vector_vertex_node[isub][i][1] =
41713  sub_tmp_vector_vertex_node[isub][i][2];
41714  }
41715  }
41716  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41717 
41718  // We already have the info. for the sub-boundaries (if necessary)
41719  // and then we can create the sub-boundaries representations to
41720  // ease the generation of the mesh by Triangle
41721 
41722  // --------- Stuff for the sub_boundaries ----- End section ------------
41723 #endif // OOMPH_HAS_MPI
41724 
41725  // *********************************************************************
41726  // 4) Check for contiguousness
41727  // *********************************************************************
41728 #ifdef OOMPH_HAS_MPI
41729  // Only perform this checking if the mesh is not distributed
41730  // When the mesh is distributed the polylines continuity is
41731  // addressed with the sort_polylines_helper() method
41732  if (!this->is_mesh_distributed())
41733 #endif
41734  {
41735  if (p > 0)
41736  {
41737  // Final end point of previous line
41738  Vector<double> final_vertex_of_previous_segment;
41739  unsigned n_prev_vertex =
41740  polygon_pt->curve_section_pt(p - 1)->nvertex();
41741  final_vertex_of_previous_segment =
41742  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
41743  1);
41744 
41745  unsigned prev_seg_boundary_id =
41746  polygon_pt->curve_section_pt(p - 1)->boundary_id();
41747 
41748  // Find the error between the final vertex of the previous
41749  // line and the first vertex of the current line
41750  double error = 0.0;
41751  for (unsigned i = 0; i < 2; i++)
41752  {
41753  const double dist = final_vertex_of_previous_segment[i] -
41754  (*vector_vertex_node.begin())[i];
41755  error += dist * dist;
41756  }
41757  error = sqrt(error);
41758 
41759  // If the error is bigger than the tolerance then
41760  // we probably need to reverse, but better check
41761  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41762  {
41763  // Find the error between the final vertex of the previous
41764  // line and the last vertex of the current line
41765  double rev_error = 0.0;
41766  for (unsigned i = 0; i < 2; i++)
41767  {
41768  const double dist = final_vertex_of_previous_segment[i] -
41769  (*--vector_vertex_node.end())[i];
41770  rev_error += dist * dist;
41771  }
41772  rev_error = sqrt(rev_error);
41773 
41774  if (rev_error >
41775  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41776  {
41777  // It could be possible that the first segment be reversed and we
41778  // did not notice it because this check does not apply for the
41779  // first segment. We can verify if the first segment is reversed
41780  // by using the vertex number 1
41781  if (p == 1)
41782  {
41783  // Initial end point of previous line
41784  Vector<double> initial_vertex_of_previous_segment;
41785 
41786  initial_vertex_of_previous_segment =
41787  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
41788 
41789  unsigned prev_seg_boundary_id =
41790  polygon_pt->curve_section_pt(p - 1)->boundary_id();
41791 
41792  // Find the error between the initial vertex of the previous
41793  // line and the first vertex of the current line
41794  double error = 0.0;
41795  for (unsigned i = 0; i < 2; i++)
41796  {
41797  const double dist = initial_vertex_of_previous_segment[i] -
41798  (*vector_vertex_node.begin())[i];
41799  error += dist * dist;
41800  }
41801  error = sqrt(error); // Reversed only the previous one
41802 
41803  // If the error is bigger than the tolerance then
41804  // we probably need to reverse, but better check
41805  if (error >
41806  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41807  {
41808  // Find the error between the final vertex of the previous
41809  // line and the last vertex of the current line
41810  double rev_error = 0.0;
41811  for (unsigned i = 0; i < 2; i++)
41812  {
41813  const double dist = initial_vertex_of_previous_segment[i] -
41814  (*--vector_vertex_node.end())[i];
41815  rev_error += dist * dist;
41816  }
41817  rev_error =
41818  sqrt(rev_error); // Reversed both the current one and
41819  // the previous one
41820 
41821  if (rev_error >
41822  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41823  {
41824  std::ostringstream error_stream;
41825  error_stream
41826  << "The distance between the first node of the current\n"
41827  << "line segment (boundary " << bound
41828  << ") and either end of "
41829  << "the previous line segment\n"
41830  << "(boundary " << prev_seg_boundary_id
41831  << ") is bigger than "
41832  << "the desired tolerance "
41833  << ToleranceForVertexMismatchInPolygons::Tolerable_error
41834  << ".\n"
41835  << "This suggests that the polylines defining the "
41836  "polygonal\n"
41837  << "representation are not properly ordered.\n"
41838  << "Fail on last vertex of polyline: ("
41839  << prev_seg_boundary_id
41840  << ") and\nfirst vertex of polyline (" << bound
41841  << ").\nThis should have failed when first trying to"
41842  << " construct the\npolygon.\n";
41843  throw OomphLibError(
41844  error_stream.str(),
41845  "RefineableTriangleMesh::update_polygon_after_restart()",
41846  OOMPH_EXCEPTION_LOCATION);
41847  }
41848  else
41849  {
41850  // Reverse both
41851  // Reverse the current vector to line up with the previous
41852  // one
41853  std::reverse(vector_vertex_node.begin(),
41854  vector_vertex_node.end());
41855  polygon_pt->polyline_pt(p - 1)->reverse();
41856  }
41857  }
41858  else
41859  {
41860  // Reverse the previous one
41861  polygon_pt->polyline_pt(p - 1)->reverse();
41862  }
41863 
41864  } // if p == 1
41865  else
41866  {
41867  std::ostringstream error_stream;
41868  error_stream
41869  << "The distance between the first node of the current\n"
41870  << "line segment (boundary " << bound
41871  << ") and either end of "
41872  << "the previous line segment\n"
41873  << "(boundary " << prev_seg_boundary_id
41874  << ") is bigger than the "
41875  << "desired tolerance "
41876  << ToleranceForVertexMismatchInPolygons::Tolerable_error
41877  << ".\n"
41878  << "This suggests that the polylines defining the polygonal\n"
41879  << "representation are not properly ordered.\n"
41880  << "Fail on last vertex of polyline: ("
41881  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
41882  << bound << ").\n"
41883  << "This should have failed when first trying to construct "
41884  "the\n"
41885  << "polygon.\n";
41886  throw OomphLibError(
41887  error_stream.str(),
41888  "RefineableTriangleMesh::update_polygon_after_restart()",
41889  OOMPH_EXCEPTION_LOCATION);
41890  }
41891  }
41892  else
41893  {
41894  // Reverse the current vector to line up with the previous one
41895  std::reverse(vector_vertex_node.begin(),
41896  vector_vertex_node.end());
41897  }
41898  } // error
41899  } // p > 0
41900  } // is mesh not distributed
41901 
41902  // *********************************************************************
41903  // 5) Update the polylines representation
41904  // *********************************************************************
41905  // if (applied_area_length_constraint)
41906  // If only applied when there is a change then it keeps the
41907  // previous polyline representation, it means, it does not delete
41908  // the boundaries that are not part of the domain. We must update
41909  // the boundary representation
41910  {
41911  n_vertex = vector_vertex_node.size();
41912 
41913  // Now update the polyline according to the new vertices
41914  // The new one representation
41915  TriangleMeshPolyLine* tmp_polyline_pt =
41916  new TriangleMeshPolyLine(vector_vertex_node, bound);
41917 
41918  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41919  // {
41920  // DEBP(h);
41921  // DEBP(vector_vertex_node[h][0]);
41922  // DEBP(vector_vertex_node[h][1]);
41923  // }
41924 
41925  // Create a temporal "curve section" version of the recently created
41926  // polyline
41927  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
41928 
41929  // Tolerance below which the middle point can be deleted
41930  // (ratio of deflection to element length)
41931  double unrefinement_tolerance =
41932  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41933 
41934  // Tolerance to add points
41935  double refinement_tolerance =
41936  polygon_pt->polyline_pt(p)->refinement_tolerance();
41937 
41938  // Establish refinement and unrefinement tolerance
41939  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
41940  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
41941 
41942  // Establish the maximum length constraint
41943  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41944  tmp_polyline_pt->set_maximum_length(maximum_length);
41945 
41946  if (n_vertex >= 2)
41947  {
41948  // Pass the connection information from the old polyline to the
41949  // new one
41950  this->copy_connection_information(polygon_pt->polyline_pt(p),
41951  tmp_curve_section_pt);
41952  }
41953 
41954  // Now update the polyline according to the new vertices but
41955  // first check if the object is allowed to delete the representation
41956  // or if it should be done by other object
41957  bool delete_it_on_destructor = false;
41958 
41959  std::set<TriangleMeshCurveSection*>::iterator it =
41960  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41961 
41962  if (it != this->Free_curve_section_pt.end())
41963  {
41964  this->Free_curve_section_pt.erase(it);
41965  delete polygon_pt->curve_section_pt(p);
41966  delete_it_on_destructor = true;
41967  }
41968 
41969  // *****************************************************************
41970  // Copying the new representation
41971  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41972 
41973  // Update the Boundary - Polyline map
41974  this->Boundary_curve_section_pt[bound] =
41975  polygon_pt->curve_section_pt(p);
41976 
41977  if (delete_it_on_destructor)
41978  {
41979  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41980  }
41981 
41982 #ifdef OOMPH_HAS_MPI
41983  // --------- Stuff for the sub_boundaries ----- Begin section --------
41984  // Verify if need to deal with sub_boundaries
41985  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41986  {
41987  // Create temporary representations for the boundaries, only to
41988  // create the mesh when calling Triangle
41989  // Clear all previous stored data
41990  this->Boundary_subpolylines[bound].clear();
41991  // Now create storage for the sub-boundaries
41992  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41993  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41994  {
41995  // Now update the polyline according to the sub set of
41996  // vertices, set the chunk number of the polyline
41997  TriangleMeshPolyLine* sub_tmp_polyline_pt =
41998  new TriangleMeshPolyLine(
41999  sub_vector_vertex_node[isub], bound, isub);
42000 
42001  // Add the sub-polyline to the container to represent the boundary
42002  // in parts
42003  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42004 
42005  // No need to send the unrefinement/refinement and maximum
42006  // length constraints since these are only temporary
42007  // representations. These polylines can be deleted once the
42008  // new polygons that represent the distributed domain have
42009  // been created
42010 
42011  } // for (isub < nsub_boundaries)
42012 
42013  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42014  // --------- Stuff for the sub_boundaries ----- End section ---------
42015 #endif // OOMPH_HAS_MPI
42016 
42017  } // update polyline representation
42018 
42019  // Delete the allocated memory for the geometric object that
42020  // represents the curvilinear boundary
42021  delete mesh_geom_obj_pt;
42022 
42023  } // npolyline
42024 
42025  // Cleanup the face mesh
42026  for (unsigned p = 0; p < n_polyline; p++)
42027  {
42028  face_mesh_pt[p]->flush_node_storage();
42029  delete face_mesh_pt[p];
42030  }
42031  }
42032 
42033 
42034  //======================================================================
42035  /// \short Updates the open curve representation after restart
42036  //======================================================================
42037  template<class ELEMENT>
42039  TriangleMeshOpenCurve*& open_curve_pt)
42040  {
42041  // **********************************************************************
42042  // 1) Get the vertices along the boundaries ids of the polylines and
42043  // update them
42044  // **********************************************************************
42045 
42046  // (1.1) Get the face mesh representation
42047  Vector<Mesh*> face_mesh_pt;
42048  get_face_mesh_representation(open_curve_pt, face_mesh_pt);
42049 
42050  // (1.2) Create vertices of the polylines by using the vertices of the
42051  // FaceElements
42052  Vector<double> vertex_coord(3); // zeta,x,y
42053  Vector<double> bound_left(1);
42054  Vector<double> bound_right(1);
42055 
42056  const unsigned ncurve_section = open_curve_pt->ncurve_section();
42057  // Go for each curve section
42058  for (unsigned cs = 0; cs < ncurve_section; cs++)
42059  {
42060  // Get the MeshAsGeomObject representation just once per polyline,
42061  // this object is only used by the
42062  // refine_boundary_constrained_by_target_area() method. We get it here
42063  // to ensure that all processors (in a distributed context) get this
42064  // representation just once, and because an AllToAll MPI communication
42065  // is used in this calling
42066  MeshAsGeomObject* mesh_geom_obj_pt =
42067  new MeshAsGeomObject(face_mesh_pt[cs]);
42068 
42069  // Get the boundary id
42070  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
42071 
42072  /// Use a vector of vector for vertices and target areas to deal
42073  /// with the cases when the boundaries are split bn the
42074  /// distribution process. Internal boundaries may be completely or
42075  /// partially overlapped by shared boundaries
42076 
42077  // Loop over the face elements and add their vertices (they are
42078  // automatically sorted because of the set)
42079  const unsigned nface_element = face_mesh_pt[cs]->nelement();
42080  // Store the non halo elements and the element at the other side of
42081  // the boundary (whatever it be halo or not), the first will be the
42082  // ones from which we will get the vertices (in even position)
42083  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
42084 
42085  // Map to store the index of the face element on a boundary
42086  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
42087 
42088  // Map to know the already sorted face elements
42089  std::map<FiniteElement*, bool> face_element_done;
42090 
42091  for (unsigned ef = 0; ef < nface_element; ++ef)
42092  {
42093  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
42094 
42095  // Skip the halo elements (not used as base elements, only
42096  // include those elements which one of its counterparts -- at the
42097  // other side of the boundary -- is non halo)
42098 #ifdef OOMPH_HAS_MPI
42099  if (this->is_mesh_distributed())
42100  {
42101  // Only work with non-halo elements
42102  if (ele_face_pt->is_halo())
42103  {
42104  continue;
42105  }
42106  }
42107 #endif
42108 
42109  // Check if not already done
42110  if (!face_element_done[ele_face_pt])
42111  {
42112  // Add the element and look for the element at the other side
42113  // of the boundary to add it immediately after the new added
42114  // element
42115  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
42116  // Create the map of the face element with the index
42117  face_element_index_on_boundary[ele_face_pt] = ef;
42118  // Mark the current element as done
42119  face_element_done[ele_face_pt] = true;
42120  // Get the number of nodes
42121  const unsigned nnodes = ele_face_pt->nnode();
42122  // Get the left and right node to look for the elements at the
42123  // other side of the boundary
42124  Node* left_node_pt = ele_face_pt->node_pt(0);
42125  Node* right_node_pt = ele_face_pt->node_pt(nnodes - 1);
42126 
42127 #ifdef PARANOID
42128  // Flag to know if the element at the other side of the
42129  // boundary was found
42130  bool found_other_side_face_ele = false;
42131 #endif
42132  for (unsigned iface = 0; iface < nface_element; iface++)
42133  {
42134  // Get the candidate face element
42135  FiniteElement* cele_face_pt =
42136  face_mesh_pt[cs]->finite_element_pt(iface);
42137  // Check if not already done
42138  if (!face_element_done[cele_face_pt])
42139  {
42140  Node* cleft_node_pt = cele_face_pt->node_pt(0);
42141  Node* cright_node_pt = cele_face_pt->node_pt(nnodes - 1);
42142 
42143  // Check if the nodes are the same
42144  if ((left_node_pt == cleft_node_pt &&
42145  right_node_pt == cright_node_pt) ||
42146  (left_node_pt == cright_node_pt &&
42147  right_node_pt == cleft_node_pt))
42148  {
42149  // Add the element to the storage
42150  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
42151  // ... and mark the element as done
42152  face_element_done[cele_face_pt] = true;
42153  // Create the map of the face element with the index
42154  face_element_index_on_boundary[cele_face_pt] = iface;
42155 #ifdef PARANOID
42156  // Set the flag of found other side face element
42157  found_other_side_face_ele = true;
42158 #endif
42159  break;
42160  }
42161  }
42162  } // (iface < nface_element)
42163 
42164 #ifdef PARANOID
42165  if (!found_other_side_face_ele)
42166  {
42167  std::ostringstream error_message;
42168  error_message
42169  << "The face element at the other side of the boundary (" << bound
42170  << ") was not found!!\n"
42171  << "These are the nodes of the face element:\n"
42172  << "(" << left_node_pt->x(0) << ", " << left_node_pt->x(1) << ") "
42173  << "and (" << right_node_pt->x(0) << "," << right_node_pt->x(1)
42174  << ")\n\n";
42175  throw OomphLibError(
42176  error_message.str(),
42177  "RefineableTriangleMesh::update_open_curve_after_restart()",
42178  OOMPH_EXCEPTION_LOCATION);
42179  }
42180 #endif
42181  } // if (!face_ele_done[ele_face_pt])
42182 
42183  } // (ef < nface_element)
42184 
42185  // Clear the map of the already done face elements
42186  // This will now be used to sort the face elements
42187  face_element_done.clear();
42188 
42189  // Set of coordinates that are on the boundary
42190  // The entries are sorted on first entry in vector which stores
42191  // the boundary coordinate so the vertices come out in order!
42192  std::set<Vector<double>> vertex_nodes;
42193 
42194  // Vector to store the vertices, transfer the sorted vertices from the
42195  // set to this vector, --- including the z-value ---
42196  Vector<Vector<double>> tmp_vector_vertex_node;
42197 
42198  // Vector to store the coordinates of the polylines, same as the
42199  // tmp_vector_vertex_node vector (after adding more nodes) but
42200  // --- without the z-value ---, used to re-generate the polylines
42201  Vector<Vector<double>> vector_vertex_node;
42202 
42203 #ifdef OOMPH_HAS_MPI
42204  // Indicates if the set of vertices give rise to a internal
42205  // boundary that will be used as shared boundary or as normal
42206  // internal boundary -- Only used to deal with internal boundaries
42207  // in a distributed scheme
42208  std::vector<bool> internal_to_shared_boundary;
42209 
42210  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
42211  // Set of coordinates that are on the boundary (splitted boundary version)
42212  // The first vector is used to allocate the points for each sub-boundary
42213  // Set entries are ordered on first entry in vector which stores
42214  // the boundary coordinate so the vertices come out in order!
42215  Vector<std::set<Vector<double>>> sub_vertex_nodes;
42216 
42217  // Vector to store the vertices, transfer the sorted vertices from the
42218  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
42219  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
42220 
42221  // Vector to store the coordinates of the polylines that will represent
42222  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
42223  // but --- without the z-value ---, used to generate the sub-polylines
42224  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
42225 
42226  // --------- Stuff to deal with splitted boundaries ----------- End ------
42227 #endif
42228 
42229  // Sort face elements, separate those with both nonhalo face
42230  // elements from those with one halo and one nonhalo face element
42231 
42232  // Number of done face elements
42233  unsigned nsorted_face_elements = 0;
42234 
42235 #ifdef OOMPH_HAS_MPI
42236  // Counter for sub_boundaries
42237  unsigned nsub_boundaries = 0;
42238 #endif // #ifdef OOMPH_HAS_MPI
42239 
42240  // Total number of non halo double face element
42241  const unsigned nnon_halo_doubled_face_ele =
42242  non_halo_doubled_face_element_pt.size();
42243 
42244  // Continue until all the face elements have been sorted
42245  // This while is to deal with the cases of splitted boundaries
42246  while (nsorted_face_elements < nnon_halo_doubled_face_ele)
42247  {
42248  // Get and initial face element
42249  FiniteElement* ele_face_pt = 0;
42250  FiniteElement* repeated_ele_face_pt = 0;
42251 #ifdef PARANOID
42252  bool found_initial_face_element = false;
42253 #endif
42254 
42255  // Flag to know if we are working with a face element which the
42256  // face element at the other side of the boundary is also non
42257  // halo
42258  bool both_root_face_elements_are_nonhalo = false;
42259 
42260  unsigned iface = 0;
42261  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface += 2)
42262  {
42263  ele_face_pt = non_halo_doubled_face_element_pt[iface];
42264  // If not done then take it as initial face element
42265  if (!face_element_done[ele_face_pt])
42266  {
42267  // Mark it as done
42268  face_element_done[ele_face_pt] = true;
42269  // Get the other side boundary face element
42270  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface + 1];
42271  // ... also mark as done the repeated face element
42272  face_element_done[repeated_ele_face_pt] = true;
42273 
42274 #ifdef OOMPH_HAS_MPI
42275  if (!repeated_ele_face_pt->is_halo())
42276  {
42277  both_root_face_elements_are_nonhalo = true;
42278  }
42279 #endif // #ifdef OOMPH_HAS_MPI
42280 
42281  // Plus two because internal boundaries have
42282  // two face elements per each edge
42283  nsorted_face_elements += 2;
42284  iface += 2;
42285 #ifdef PARANOID
42286  // And set the flag to true
42287  found_initial_face_element = true;
42288 #endif
42289  break;
42290  }
42291  }
42292 
42293 #ifdef PARANOID
42294  if (!found_initial_face_element)
42295  {
42296  std::ostringstream error_message;
42297  error_message << "Could not find an initial face element for the "
42298  "current segment\n";
42299  // << "----- Possible memory leak -----\n";
42300  throw OomphLibError(error_message.str(),
42301  OOMPH_CURRENT_FUNCTION,
42302  OOMPH_EXCEPTION_LOCATION);
42303  }
42304 #endif
42305 
42306  // Local set of coordinates that are on the boundary Set entries
42307  // are ordered on first entry in vector which stores the boundary
42308  // coordinate so the vertices come out in order
42309  std::set<Vector<double>> local_vertex_nodes;
42310 
42311  // Vector to store the vertices, transfer the sorted vertices from the
42312  // set (local) to this vector (local), --- including the z-value ---
42313  Vector<Vector<double>> local_tmp_vector_vertex_node;
42314 
42315  // ------------------------------------------------------------------
42316  // ------------------------------------------------------------------
42317  // Add the vertices of the initial face element to the set of local
42318  // sorted vertices
42319  // ------------------------------------------------------------------
42320  // ------------------------------------------------------------------
42321  const unsigned nnode = ele_face_pt->nnode();
42322  // Add the left-hand node to the set:
42323  // Boundary coordinate
42324  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
42325  vertex_coord[0] = bound_left[0];
42326 
42327  // Actual coordinates
42328  for (unsigned i = 0; i < 2; i++)
42329  {
42330  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
42331  }
42332  local_vertex_nodes.insert(vertex_coord);
42333 
42334  // Add the right-hand node to the set:
42335  // Boundary coordinate
42336  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
42337  bound, bound_right);
42338  vertex_coord[0] = bound_right[0];
42339 
42340  // Actual coordinates
42341  for (unsigned i = 0; i < 2; i++)
42342  {
42343  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
42344  }
42345  local_vertex_nodes.insert(vertex_coord);
42346 
42347  // The initial and final node on the set
42348  Node* first_node_pt = ele_face_pt->node_pt(0);
42349  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
42350 
42351  // Continue iterating if a new face element has been added to the
42352  // list
42353  bool face_element_added = false;
42354 
42355  // While a new face element has been added to the set of sorted
42356  // face elements then re-iterate
42357  do
42358  {
42359  // Start from the next face elements since we have already
42360  // added the previous one as the initial face element (any
42361  // previous face element had to be added on previous
42362  // iterations)
42363  for (unsigned iiface = iface; iiface < nnon_halo_doubled_face_ele;
42364  iiface += 2)
42365  {
42366  face_element_added = false;
42367  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42368 
42369  // Check that the face element with which we are working has
42370  // the same conditions as the root face element (both faces
42371  // are nonhalo or one face is halo and the other nonhalo)
42372 
42373  // Get the face element at the other side of the boundary
42374  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface + 1];
42375  bool both_face_elements_are_nonhalo = false;
42376 
42377 #ifdef OOMPH_HAS_MPI
42378  if (!repeated_ele_face_pt->is_halo())
42379  {
42380  both_face_elements_are_nonhalo = true;
42381  }
42382 #endif // #ifdef OOMPH_HAS_MPI
42383 
42384  if (!face_element_done[ele_face_pt] &&
42385  (both_face_elements_are_nonhalo ==
42386  both_root_face_elements_are_nonhalo))
42387  {
42388  // Get each individual node to check if they are contiguous
42389  const unsigned nlnode = ele_face_pt->nnode();
42390  Node* left_node_pt = ele_face_pt->node_pt(0);
42391  Node* right_node_pt = ele_face_pt->node_pt(nlnode - 1);
42392 
42393  if (left_node_pt == first_node_pt)
42394  {
42395  first_node_pt = right_node_pt;
42396  face_element_added = true;
42397  }
42398  else if (left_node_pt == last_node_pt)
42399  {
42400  last_node_pt = right_node_pt;
42401  face_element_added = true;
42402  }
42403  else if (right_node_pt == first_node_pt)
42404  {
42405  first_node_pt = left_node_pt;
42406  face_element_added = true;
42407  }
42408  else if (right_node_pt == last_node_pt)
42409  {
42410  last_node_pt = left_node_pt;
42411  face_element_added = true;
42412  }
42413 
42414  if (face_element_added)
42415  {
42416  // Add the left-hand node to the set:
42417  // Boundary coordinate
42418  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
42419  vertex_coord[0] = bound_left[0];
42420 
42421  // Actual coordinates
42422  for (unsigned i = 0; i < 2; i++)
42423  {
42424  vertex_coord[i + 1] = left_node_pt->x(i);
42425  }
42426  local_vertex_nodes.insert(vertex_coord);
42427 
42428  // Add the right-hand nodes to the set:
42429  // Boundary coordinate
42430  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
42431  vertex_coord[0] = bound_right[0];
42432 
42433  // Actual coordinates
42434  for (unsigned i = 0; i < 2; i++)
42435  {
42436  vertex_coord[i + 1] = right_node_pt->x(i);
42437  }
42438  local_vertex_nodes.insert(vertex_coord);
42439 
42440  // Mark as done only if one of its nodes has been
42441  // added to the list
42442  face_element_done[ele_face_pt] = true;
42443  // .. also mark as done the face element at the othe side of
42444  // the boundary
42445  repeated_ele_face_pt =
42446  non_halo_doubled_face_element_pt[iiface + 1];
42447  face_element_done[repeated_ele_face_pt] = true;
42448  // ... and increase the number of sorted face elements
42449  nsorted_face_elements += 2;
42450 
42451  break;
42452  }
42453 
42454  } // if (!face_element_done[[ele_face_pt])
42455  } // for (iiface<nnon_halo_doubled_face_ele)
42456  } while (face_element_added &&
42457  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42458 
42459  // -------------------------------------------------------------
42460  // At this point we already have a sorted set of nodes and can
42461  // be used to peform the unrefinement and refinement procedures
42462  // -------------------------------------------------------------
42463 
42464  // Get the number of nodes on the list
42465  const unsigned nlocal_nodes = local_vertex_nodes.size();
42466  // Change representation to vector for easy of handling ...
42467  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42468 
42469  // Copy the vertices of the nodes
42470  unsigned counter = 0;
42471  std::set<Vector<double>>::iterator it_vertex;
42472  for (it_vertex = local_vertex_nodes.begin();
42473  it_vertex != local_vertex_nodes.end();
42474  it_vertex++)
42475  {
42476  local_tmp_vector_vertex_node[counter].resize(3);
42477  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42478  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42479  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42480  counter++;
42481  }
42482 
42483  // The unrefinement and refinement process needs to be applied
42484  // from the bottom-left node since the internal open curve could
42485  // lie on the shared boundaries
42486  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] <
42487  local_tmp_vector_vertex_node[0][2])
42488  {
42489  std::reverse(local_tmp_vector_vertex_node.begin(),
42490  local_tmp_vector_vertex_node.end());
42491  }
42492  else if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] ==
42493  local_tmp_vector_vertex_node[0][2])
42494  {
42495  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][1] <
42496  local_tmp_vector_vertex_node[0][1])
42497  {
42498  std::reverse(local_tmp_vector_vertex_node.begin(),
42499  local_tmp_vector_vertex_node.end());
42500  }
42501  }
42502 
42503  // ****************************************************************
42504  // 3) Create the vertices along the boundary using the target
42505  // area to define the distance among them
42506  // ****************************************************************
42507 
42508  // Clear the local containter to recover the nodes ordered using
42509  // the zeta value
42510  local_vertex_nodes.clear();
42511 
42512  // At the end of each unrefinement/refinement step store the new
42513  // nodes on the set that will give rise to the vertices of the
42514  // new polyline representation
42515  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42516  for (unsigned i = 0; i < nnew_nodes; i++)
42517  {
42518  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42519  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42520  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42521  vertex_nodes.insert(vertex_coord); // Global container
42522  local_vertex_nodes.insert(vertex_coord);
42523  }
42524 
42525 #ifdef OOMPH_HAS_MPI
42526  if (this->is_mesh_distributed())
42527  {
42528  // Add the set of vertices for the boundary, this will help to
42529  // detect if we need to deal with sub_boundaries and
42530  // sub_polylines representations
42531  sub_vertex_nodes.push_back(local_vertex_nodes);
42532  // Increase the counter for sub_boundaries
42533  nsub_boundaries++;
42534 
42535  // Mark if the polyline created by these vertices will be used
42536  // as a shared boundary or as an internal boundary
42537  if (both_root_face_elements_are_nonhalo)
42538  {
42539  internal_to_shared_boundary.push_back(false);
42540  }
42541  else
42542  {
42543  internal_to_shared_boundary.push_back(true);
42544  }
42545  }
42546 #endif
42547 
42548  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42549  // This while is in charge of sorting all the face elements to
42550  // create the new representation of the polyline (also deals
42551  // with the sub-boundary cases)
42552 
42553  // Now turn into vector for ease of handling...
42554  const unsigned npoly_vertex = vertex_nodes.size();
42555  tmp_vector_vertex_node.resize(npoly_vertex);
42556  unsigned count = 0;
42557  std::set<Vector<double>>::iterator it;
42558  for (it = vertex_nodes.begin(); it != vertex_nodes.end(); ++it)
42559  {
42560  tmp_vector_vertex_node[count].resize(3);
42561  tmp_vector_vertex_node[count][0] = (*it)[0];
42562  tmp_vector_vertex_node[count][1] = (*it)[1];
42563  tmp_vector_vertex_node[count][2] = (*it)[2];
42564  ++count;
42565  }
42566 
42567 #ifdef OOMPH_HAS_MPI
42568  // Check that the number of set of vertices marked to be shared or
42569  // internal boundaries be the same as the total number of
42570  // sub-boundaries
42571 #ifdef PARANOID
42572  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42573  const unsigned ninternal_to_shared_boundaries =
42574  internal_to_shared_boundary.size();
42575  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42576  {
42577  std::ostringstream error_message;
42578  error_message
42579  << "The number of found sub-boundaries and the number of marked "
42580  << "internal\nboundaries are different\n"
42581  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
42582  << "Number of marked internal boundaries: ("
42583  << ninternal_to_shared_boundaries << ")\n\n";
42584  throw OomphLibError(
42585  error_message.str(),
42586  "RefineableTriangleMesh::update_open_curve_after_restart()",
42587  OOMPH_EXCEPTION_LOCATION);
42588  }
42589 #endif
42590 
42591  // --------- Stuff for the sub_boundaries ----- Begin section -------
42592 #ifdef PARANOID
42593  if (nsub_boundaries_set != nsub_boundaries)
42594  {
42595  std::ostringstream error_message;
42596  error_message
42597  << "The number of found sub-boundaries and the number of counted\n"
42598  << "sub-boundaries are different:\n"
42599  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
42600  << "Number of counted sub-boundaries: (" << nsub_boundaries
42601  << ")\n\n";
42602  throw OomphLibError(
42603  error_message.str(),
42604  "RefineableTriangleMesh::update_open_curve_after_restart()",
42605  OOMPH_EXCEPTION_LOCATION);
42606  }
42607 #endif
42608 
42609  // Verify if need to deal with sub_boundaries
42610  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42611  {
42612  // Mark the boundary as been splitted in the partition process
42613  this->Boundary_was_splitted[bound] = true;
42614  // Resize the vector to store the info. of sub-boundaries
42615  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42616  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42617  {
42618  // Turn info. into vector for ease of handling...
42619  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42620  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42621  unsigned subcount = 0;
42622  std::set<Vector<double>>::iterator subit;
42623  for (subit = sub_vertex_nodes[isub].begin();
42624  subit != sub_vertex_nodes[isub].end();
42625  ++subit)
42626  {
42627  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42628  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42629  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42630  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42631  ++subcount;
42632  }
42633  }
42634  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42635  // --------- Stuff for the sub_boundaries ----- End section ----------
42636 #endif // OOMPH_HAS_MPI
42637 
42638  // For further processing the three-dimensional vector has to be
42639  // reduced to a two-dimensional vector
42640  unsigned n_vertex = tmp_vector_vertex_node.size();
42641 
42642  // Resize the vector for vectices
42643  vector_vertex_node.resize(n_vertex);
42644  for (unsigned i = 0; i < n_vertex; i++)
42645  {
42646  vector_vertex_node[i].resize(2);
42647  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
42648  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
42649  }
42650 
42651 #ifdef OOMPH_HAS_MPI
42652  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42653  // Verify if need to deal with sub_boundaries
42654  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42655  {
42656  // For further processing the three-dimensional vector
42657  // has to be reduced to a two-dimensional vector
42658  // Resize the vector to store the info. of sub-boundaries
42659  sub_vector_vertex_node.resize(nsub_boundaries);
42660  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42661  {
42662  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
42663  // Resize the vector for vectices
42664  sub_vector_vertex_node[isub].resize(subn_vertex);
42665  for (unsigned i = 0; i < subn_vertex; i++)
42666  {
42667  sub_vector_vertex_node[isub][i].resize(2);
42668  sub_vector_vertex_node[isub][i][0] =
42669  sub_tmp_vector_vertex_node[isub][i][1];
42670  sub_vector_vertex_node[isub][i][1] =
42671  sub_tmp_vector_vertex_node[isub][i][2];
42672  }
42673  }
42674  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42675 
42676  // We already have the info. for the sub-boundaries (if necessary) and
42677  // then we can create the sub-boundaries representations to ease the
42678  // generation of the mesh by Triangle
42679 
42680  // --------- Stuff for the sub_boundaries ----- End section ------------
42681 #endif // OOMPH_HAS_MPI
42682 
42683  // *********************************************************************
42684  // 4) Check for contiguousness
42685  // *********************************************************************
42686 #ifdef OOMPH_HAS_MPI
42687  // Only perform this checking if the mesh is not distributed
42688  // When the mesh is distributed the polylines continuity is
42689  // addressed with the sort_polylines_helper() method
42690  if (!this->is_mesh_distributed())
42691 #endif
42692  {
42693  if (cs > 0)
42694  {
42695  // Final end point of previous line
42696  Vector<double> final_vertex_of_previous_segment;
42697  unsigned n_prev_vertex =
42698  open_curve_pt->curve_section_pt(cs - 1)->nvertex();
42699  final_vertex_of_previous_segment =
42700  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(
42701  n_prev_vertex - 1);
42702 
42703  unsigned prev_seg_boundary_id =
42704  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
42705 
42706  // Find the error between the final vertex of the previous
42707  // line and the first vertex of the current line
42708  double error = 0.0;
42709  for (unsigned i = 0; i < 2; i++)
42710  {
42711  const double dist = final_vertex_of_previous_segment[i] -
42712  (*vector_vertex_node.begin())[i];
42713  error += dist * dist;
42714  }
42715  error = sqrt(error);
42716 
42717  // If the error is bigger than the tolerance then
42718  // we probably need to reverse, but better check
42719  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42720  {
42721  // Find the error between the final vertex of the previous
42722  // line and the last vertex of the current line
42723  double rev_error = 0.0;
42724  for (unsigned i = 0; i < 2; i++)
42725  {
42726  const double dist = final_vertex_of_previous_segment[i] -
42727  (*--vector_vertex_node.end())[i];
42728  rev_error += dist * dist;
42729  }
42730  rev_error = sqrt(rev_error);
42731 
42732  if (rev_error >
42733  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42734  {
42735  // It could be possible that the first segment be reversed and we
42736  // did not notice it because this check does not apply for the
42737  // first segment. We can verify if the first segment is reversed
42738  // by using the vertex number 1
42739  if (cs == 1)
42740  {
42741  // Initial end point of previous line
42742  Vector<double> initial_vertex_of_previous_segment;
42743 
42744  initial_vertex_of_previous_segment =
42745  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(0);
42746 
42747  unsigned prev_seg_boundary_id =
42748  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
42749 
42750  // Find the error between the initial vertex of the previous
42751  // line and the first vertex of the current line
42752  double error = 0.0;
42753  for (unsigned i = 0; i < 2; i++)
42754  {
42755  const double dist = initial_vertex_of_previous_segment[i] -
42756  (*vector_vertex_node.begin())[i];
42757  error += dist * dist;
42758  }
42759  error = sqrt(error); // Reversed only the previous one
42760 
42761  // If the error is bigger than the tolerance then
42762  // we probably need to reverse, but better check
42763  if (error >
42764  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42765  {
42766  // Find the error between the final vertex of the previous
42767  // line and the last vertex of the current line
42768  double rev_error = 0.0;
42769  for (unsigned i = 0; i < 2; i++)
42770  {
42771  const double dist = initial_vertex_of_previous_segment[i] -
42772  (*--vector_vertex_node.end())[i];
42773  rev_error += dist * dist;
42774  }
42775  rev_error = sqrt(rev_error); // Reversed both the current
42776  // one and the previous one
42777 
42778  if (rev_error >
42779  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42780  {
42781  std::ostringstream error_stream;
42782  error_stream
42783  << "The distance between the first node of the current\n"
42784  << "line segment (boundary " << bound
42785  << ") and either end of "
42786  << "the previous line segment\n"
42787  << "(boundary " << prev_seg_boundary_id
42788  << ") is bigger than"
42789  << " the desired tolerance "
42790  << ToleranceForVertexMismatchInPolygons::Tolerable_error
42791  << ".\n"
42792  << "This suggests that the polylines defining the "
42793  "polygonal\n"
42794  << "representation are not properly ordered.\n"
42795  << "Fail on last vertex of polyline: ("
42796  << prev_seg_boundary_id
42797  << ") and\nfirst vertex of polyline (" << bound
42798  << ").\nThis should have failed when first trying to "
42799  << "construct the\npolygon.\n";
42800  throw OomphLibError(error_stream.str(),
42801  "RefineableTriangleMesh::update_open_"
42802  "curve_after_restart()",
42803  OOMPH_EXCEPTION_LOCATION);
42804  }
42805  else
42806  {
42807  // Reverse both
42808  // Reverse the current vector to line up with the previous
42809  // one
42810  std::reverse(vector_vertex_node.begin(),
42811  vector_vertex_node.end());
42812  open_curve_pt->polyline_pt(cs - 1)->reverse();
42813  }
42814  }
42815  else
42816  {
42817  // Reverse the previous one
42818  open_curve_pt->polyline_pt(cs - 1)->reverse();
42819  }
42820 
42821  } // if (cs == 1)
42822  else
42823  {
42824  std::ostringstream error_stream;
42825  error_stream
42826  << "The distance between the first node of the current\n"
42827  << "line segment (boundary " << bound
42828  << ") and either end of "
42829  << "the previous line segment\n"
42830  << "(boundary " << prev_seg_boundary_id
42831  << ") is bigger than the "
42832  << "desired tolerance "
42833  << ToleranceForVertexMismatchInPolygons::Tolerable_error
42834  << ".\n"
42835  << "This suggests that the polylines defining the polygonal\n"
42836  << "representation are not properly ordered.\n"
42837  << "Fail on last vertex of polyline: ("
42838  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
42839  << bound << ").\n"
42840  << "This should have failed when first trying to construct "
42841  "the\n"
42842  << "polygon.\n";
42843  throw OomphLibError(
42844  error_stream.str(),
42845  "RefineableTriangleMesh::update_open_curve_after_restart()",
42846  OOMPH_EXCEPTION_LOCATION);
42847  }
42848  }
42849  else
42850  {
42851  // Reverse the current vector to line up with the previous one
42852  std::reverse(vector_vertex_node.begin(),
42853  vector_vertex_node.end());
42854  }
42855  } // error
42856  } // (cs > 0)
42857  } // is mesh not distributed
42858 
42859  // DEBP(applied_area_length_constraint);
42860  // DEBP(p);
42861  // getchar();
42862  // *********************************************************************
42863  // 5) Update the polylines representation
42864  // *********************************************************************
42865  // if (applied_area_length_constraint)
42866  // If only applied when there is a change then it keeps the
42867  // previous polyline representation, it means, it does not delete
42868  // the boundaries that are not part of the domain. We must update
42869  // the boundary representation
42870  {
42871  n_vertex = vector_vertex_node.size();
42872 
42873  // Now update the polyline according to the new vertices
42874  // The new one representation
42875  TriangleMeshPolyLine* tmp_polyline_pt =
42876  new TriangleMeshPolyLine(vector_vertex_node, bound);
42877 
42878  // Create a temporal "curve section" version of the recently created
42879  // polyline
42880  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
42881 
42882  // Tolerance below which the middle point can be deleted
42883  // (ratio of deflection to element length)
42884  double unrefinement_tolerance =
42885  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42886 
42887  // Tolerance to add points
42888  double refinement_tolerance =
42889  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42890 
42891  // Establish refinement and unrefinement tolerance
42892  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42893  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42894 
42895  // Establish the maximum length constraint
42896  double maximum_length =
42897  open_curve_pt->polyline_pt(cs)->maximum_length();
42898  tmp_polyline_pt->set_maximum_length(maximum_length);
42899 
42900  if (n_vertex >= 2)
42901  {
42902  // Pass the connection information from the old polyline to the
42903  // new one
42904  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42905  tmp_curve_section_pt);
42906  }
42907 
42908  // Now update the polyline according to the new vertices but first
42909  // check if the object is allowed to delete the representation or
42910  // if it should be done by other object
42911  bool delete_it_on_destructor = false;
42912 
42913  std::set<TriangleMeshCurveSection*>::iterator it =
42914  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42915 
42916  if (it != this->Free_curve_section_pt.end())
42917  {
42918  this->Free_curve_section_pt.erase(it);
42919  delete open_curve_pt->curve_section_pt(cs);
42920  delete_it_on_destructor = true;
42921  }
42922 
42923  // *****************************************************************
42924  // Copying the new representation
42925  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42926 
42927  // Update the Boundary - Polyline map
42928  this->Boundary_curve_section_pt[bound] =
42929  open_curve_pt->curve_section_pt(cs);
42930 
42931  if (delete_it_on_destructor)
42932  {
42933  this->Free_curve_section_pt.insert(
42934  open_curve_pt->curve_section_pt(cs));
42935  }
42936 
42937 #ifdef OOMPH_HAS_MPI
42938 
42939  // If there are not sub-boundaries mark the boundary if need to be
42940  // trated as shared or as internal boundary
42941  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42942  {
42943  // Clear all previous stored data
42944  this->Boundary_marked_as_shared_boundary[bound].clear();
42945 
42946  // .. and store the flag for the boundary
42947  this->Boundary_marked_as_shared_boundary[bound].push_back(
42948  internal_to_shared_boundary[0]);
42949  }
42950  // --------- Stuff for the sub_boundaries ----- Begin section --------
42951  // Verify if need to deal with sub_boundaries
42952  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42953  {
42954  // Create temporary representations for the boundaries, only to
42955  // create the mesh when calling Triangle
42956  // Clear all previous stored data
42957  this->Boundary_subpolylines[bound].clear();
42958  // Now create storage for the sub-boundaries
42959  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42960 
42961  // Clear all previous stored data
42962  this->Boundary_marked_as_shared_boundary[bound].clear();
42963  // Create storage to mark the internal boundaries as shared
42964  // boundaries
42965  this->Boundary_marked_as_shared_boundary[bound].resize(
42966  nsub_boundaries);
42967  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42968  {
42969  // Now update the polyline according to the sub set of
42970  // vertices, set the chunk number of the polyline
42971  TriangleMeshPolyLine* sub_tmp_polyline_pt =
42972  new TriangleMeshPolyLine(
42973  sub_vector_vertex_node[isub], bound, isub);
42974 
42975  // Add the sub-polyline to the container to represent the
42976  // boundary in parts
42977  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42978 
42979  // Copy the flag that mark the boundary as internal or as
42980  // shared bound
42981  this->Boundary_marked_as_shared_boundary[bound][isub] =
42982  internal_to_shared_boundary[isub];
42983 
42984  // No need to send the unrefinement/refinement and maximum
42985  // length constraints since these are only temporary
42986  // representations
42987  }
42988 
42989  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42990  // --------- Stuff for the sub_boundaries ----- End section ---------
42991 #endif // OOMPH_HAS_MPI
42992 
42993  } // update polyline representation
42994 
42995  // Delete the allocated memory for the geometric object
42996  // that represents the curvilinear boundary
42997  delete mesh_geom_obj_pt;
42998 
42999  } // npolyline
43000 
43001  // Cleanup the face mesh
43002  for (unsigned p = 0; p < ncurve_section; p++)
43003  {
43004  face_mesh_pt[p]->flush_node_storage();
43005  delete face_mesh_pt[p];
43006  }
43007  }
43008 
43009 #ifdef OOMPH_HAS_MPI
43010  //======================================================================
43011  /// \short Updates the shared polylines representation after restart
43012  //======================================================================
43013  template<class ELEMENT>
43015  Vector<TriangleMeshPolyLine*>& vector_polyline_pt)
43016  {
43017  // Go through all the shared boundaries/polylines
43018  const unsigned npolylines = vector_polyline_pt.size();
43019  for (unsigned pp = 0; pp < npolylines; pp++)
43020  {
43021  // Get the boundary of the current polyline
43022  const unsigned b = vector_polyline_pt[pp]->boundary_id();
43023 
43024  // Get the edges of the shared boundary elements that create the
43025  // shared boundary and store the shared boundary elements from where
43026  // were created
43027  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
43028  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
43029 
43030  // Store the nodes that define the edges
43031  Vector<Node*> halo_edge_nodes_pt;
43032  Vector<Node*> nonhalo_edge_nodes_pt;
43033 
43034  // Go through the shared boundary elements and store their edges
43035  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
43036  for (unsigned e = 0; e < nshared_bound_ele; e++)
43037  {
43038  // Get the shared boundary element
43039  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
43040 
43041  // Get the corner nodes, the first three nodes
43042  Node* first_node_pt = current_ele_pt->node_pt(0);
43043  Node* second_node_pt = current_ele_pt->node_pt(1);
43044  Node* third_node_pt = current_ele_pt->node_pt(2);
43045 
43046  // Check if the elements is halo
43047  if (!current_ele_pt->is_halo())
43048  {
43049  // Store the edges
43050  nonhalo_edge_nodes_pt.push_back(first_node_pt);
43051  nonhalo_edge_nodes_pt.push_back(second_node_pt);
43052 
43053  nonhalo_edge_nodes_pt.push_back(second_node_pt);
43054  nonhalo_edge_nodes_pt.push_back(third_node_pt);
43055 
43056  nonhalo_edge_nodes_pt.push_back(third_node_pt);
43057  nonhalo_edge_nodes_pt.push_back(first_node_pt);
43058 
43059  // Store the info. of the element used to create these edges
43060  std::pair<Node*, Node*> edge1 =
43061  std::make_pair(first_node_pt, second_node_pt);
43062  nonhalo_edge_element_pt[edge1] = current_ele_pt;
43063 
43064  std::pair<Node*, Node*> edge2 =
43065  std::make_pair(second_node_pt, third_node_pt);
43066  nonhalo_edge_element_pt[edge2] = current_ele_pt;
43067 
43068  std::pair<Node*, Node*> edge3 =
43069  std::make_pair(third_node_pt, first_node_pt);
43070  nonhalo_edge_element_pt[edge3] = current_ele_pt;
43071  }
43072  else
43073  {
43074  // Store the edges
43075  halo_edge_nodes_pt.push_back(first_node_pt);
43076  halo_edge_nodes_pt.push_back(second_node_pt);
43077 
43078  halo_edge_nodes_pt.push_back(second_node_pt);
43079  halo_edge_nodes_pt.push_back(third_node_pt);
43080 
43081  halo_edge_nodes_pt.push_back(third_node_pt);
43082  halo_edge_nodes_pt.push_back(first_node_pt);
43083 
43084  // Store the info. of the element used to create these edges
43085  std::pair<Node*, Node*> edge1 =
43086  std::make_pair(first_node_pt, second_node_pt);
43087  halo_edge_element_pt[edge1] = current_ele_pt;
43088 
43089  std::pair<Node*, Node*> edge2 =
43090  std::make_pair(second_node_pt, third_node_pt);
43091  halo_edge_element_pt[edge2] = current_ele_pt;
43092 
43093  std::pair<Node*, Node*> edge3 =
43094  std::make_pair(third_node_pt, first_node_pt);
43095  halo_edge_element_pt[edge3] = current_ele_pt;
43096  }
43097 
43098  } // for (e < nshared_bound_ele)
43099 
43100  // Filter the edges that give rise to a shared boundary
43101 
43102  // Mark the done edges
43103  std::map<std::pair<Node*, Node*>, bool> edge_done;
43104 
43105  // Storage for the edges shared by the elements
43106  Vector<std::pair<Node*, Node*>> unsorted_edges;
43107 
43108  // Storage for the elements that created the unsorted edges (two
43109  // elements, one at each side of the shared boundary)
43110  Vector<Vector<FiniteElement*>> unsorted_edges_elements_pt;
43111 
43112  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
43113  for (unsigned i = 0; i < nnonhalo_edge_nodes; i += 2)
43114  {
43115  Vector<Node*> currenti_edge(2);
43116  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
43117  currenti_edge[1] = nonhalo_edge_nodes_pt[i + 1];
43118 
43119  // Create the edge (both nodes that make the edge)
43120  std::pair<Node*, Node*> new_edge =
43121  std::make_pair(currenti_edge[0], currenti_edge[1]);
43122 
43123  if (!edge_done[new_edge])
43124  {
43125  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
43126  for (unsigned j = 0; j < nhalo_edge_nodes; j += 2)
43127  {
43128  Vector<Node*> currentj_edge(2);
43129  currentj_edge[0] = halo_edge_nodes_pt[j];
43130  currentj_edge[1] = halo_edge_nodes_pt[j + 1];
43131 
43132  // Comparing pointer of nodes
43133  if (currenti_edge[0] == currentj_edge[0] &&
43134  currenti_edge[1] == currentj_edge[1])
43135  {
43136  // Store the edge in the proper container
43137  unsorted_edges.push_back(new_edge);
43138 
43139  // Get the elements associated with the edges
43140  Vector<FiniteElement*> tmp_edge_element_pt;
43141 
43142  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
43143  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
43144 
43145  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
43146  tmp_edge_element_pt.push_back(halo_ele_pt);
43147 
43148  // Store the elements associated with the edge
43149  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
43150 
43151  // Mark the edge as done
43152  edge_done[new_edge] = true;
43153 
43154  // Break the loop for (j < nedge_node)
43155  break;
43156 
43157  } // equal edge
43158 
43159  // Comparing pointer of nodes (reversed)
43160  else if (currenti_edge[0] == currentj_edge[1] &&
43161  currenti_edge[1] == currentj_edge[0])
43162  {
43163  // Create the edge (both nodes that make the edge)
43164  std::pair<Node*, Node*> new_edge =
43165  std::make_pair(currenti_edge[0], currenti_edge[1]);
43166 
43167  // Store the edge in the proper container
43168  unsorted_edges.push_back(new_edge);
43169 
43170  // Create the (reversed) edge (both nodes that make the edge)
43171  std::pair<Node*, Node*> rev_new_edge =
43172  std::make_pair(currentj_edge[0], currentj_edge[1]);
43173 
43174  // Get the elements associated with the edge
43175  Vector<FiniteElement*> tmp_edge_element_pt;
43176 
43177  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
43178  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
43179 
43180  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
43181  tmp_edge_element_pt.push_back(halo_ele_pt);
43182 
43183  // Store the elements associated with the edge
43184  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
43185 
43186  // Mark the edge as done
43187  edge_done[new_edge] = true;
43188 
43189  // Break the loop for (j < nedge_node)
43190  break;
43191 
43192  } // if (equal edge)
43193 
43194  } // for (j < nhalo_edge_nodes)
43195 
43196  } // if (!edge_done[new_edge])
43197 
43198  } // for (i < nnonhalo_edge_nodes)
43199 
43200  // We already have the edges that make the shared boundary (and the
43201  // elements)
43202  // Sort them to create a contiguous boundary
43203 
43204  // Mark the already sorted edges
43205  std::map<std::pair<Node*, Node*>, bool> edge_sorted;
43206 
43207  const unsigned nunsorted_edges = unsorted_edges.size();
43208 
43209 #ifdef PARANOID
43210  // The number of unsorted edges must be the same as the number of
43211  // shared_boundary element / 2
43212  if (nshared_bound_ele / 2 != nunsorted_edges)
43213  {
43214  std::ostringstream error_message;
43215  error_message
43216  << "The number of shared boundary elements (" << nshared_bound_ele
43217  << ") is not the double\nof the number of unsorted edges ("
43218  << nunsorted_edges << ") for the current boundary (" << b << ")\n\n";
43219  throw OomphLibError(
43220  error_message.str(),
43221  "RefineableTriangleMesh::update_shared_curve_after_restart()",
43222  OOMPH_EXCEPTION_LOCATION);
43223  }
43224 #endif
43225 
43226  unsigned nsorted_edges = 0;
43227 
43228  // Storing for the sorting nodes extracted from the edges, and
43229  // then used to update the polyline
43230  std::list<Node*> sorted_nodes;
43231 
43232  // Storing for the edges elements
43233  std::list<FiniteElement*> sorted_edges_elements_pt;
43234 
43235  // Get the root edge
43236  std::pair<Node*, Node*> edge = unsorted_edges[0];
43237  nsorted_edges++;
43238 
43239  // Mark edge as done
43240  edge_sorted[edge] = true;
43241 
43242  // The initial and final node on the list
43243  Node* first_node_pt = edge.first;
43244  Node* last_node_pt = edge.second;
43245 
43246  // Push back on the list the new edge (nodes)
43247  sorted_nodes.push_back(first_node_pt);
43248  sorted_nodes.push_back(last_node_pt);
43249 
43250  // Store the elements for the current edge
43251  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
43252  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
43253 
43254  // Iterate while the number of sorted edges be less than the number of
43255  // unsorted edges
43256  while (nsorted_edges < nunsorted_edges)
43257  {
43258  // Flag to indicate when a node was added
43259  bool node_added = false;
43260 
43261  // Start from the next edge since we have already added the
43262  // previous one as the initial edge
43263  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
43264  {
43265  edge = unsorted_edges[iedge];
43266 
43267  // If edge not done
43268  if (!edge_sorted[edge])
43269  {
43270  // Get each individual node
43271  Node* left_node_pt = edge.first;
43272  Node* right_node_pt = edge.second;
43273 
43274  if (left_node_pt == first_node_pt)
43275  {
43276  // Push front the new node
43277  sorted_nodes.push_front(right_node_pt);
43278  first_node_pt = right_node_pt;
43279  node_added = true;
43280 
43281  // Store the elements for the current edge
43282  sorted_edges_elements_pt.push_front(
43283  unsorted_edges_elements_pt[iedge][1]);
43284  sorted_edges_elements_pt.push_front(
43285  unsorted_edges_elements_pt[iedge][0]);
43286  }
43287  else if (left_node_pt == last_node_pt)
43288  {
43289  // Push back the new node
43290  sorted_nodes.push_back(right_node_pt);
43291  last_node_pt = right_node_pt;
43292  node_added = true;
43293 
43294  // Store the elements for the current edge
43295  sorted_edges_elements_pt.push_back(
43296  unsorted_edges_elements_pt[iedge][0]);
43297  sorted_edges_elements_pt.push_back(
43298  unsorted_edges_elements_pt[iedge][1]);
43299  }
43300  else if (right_node_pt == first_node_pt)
43301  {
43302  // Push front the new node
43303  sorted_nodes.push_front(left_node_pt);
43304  first_node_pt = left_node_pt;
43305  node_added = true;
43306 
43307  // Store the elements for the current edge
43308  sorted_edges_elements_pt.push_front(
43309  unsorted_edges_elements_pt[iedge][1]);
43310  sorted_edges_elements_pt.push_front(
43311  unsorted_edges_elements_pt[iedge][0]);
43312  }
43313  else if (right_node_pt == last_node_pt)
43314  {
43315  // Push back the new node
43316  sorted_nodes.push_back(left_node_pt);
43317  last_node_pt = left_node_pt;
43318  node_added = true;
43319 
43320  // Store the elements for the current edge
43321  sorted_edges_elements_pt.push_back(
43322  unsorted_edges_elements_pt[iedge][0]);
43323  sorted_edges_elements_pt.push_back(
43324  unsorted_edges_elements_pt[iedge][1]);
43325  }
43326 
43327  if (node_added)
43328  {
43329  // Mark as done only if one of its nodes has been
43330  // added to the list
43331  edge_sorted[edge] = true;
43332  nsorted_edges++;
43333 
43334  // Break the for
43335  break;
43336  }
43337 
43338  } // if (!edge_done[edge])
43339  } // for (iedge < nunsorted_edges)
43340  } // while (nsorted_edges < nunsorted_edges)
43341 
43342  // At this point we already have a sorted list of nodes, get the
43343  // vertices from them and store them in a vector container
43344 
43345  // Get the number of nodes on the list
43346  unsigned nvertex = sorted_nodes.size();
43347  // The vector to store the vertices (assign space)
43348  Vector<Vector<double>> polyline_vertices(nvertex);
43349 
43350  // Copy the vertices of the nodes
43351  unsigned counter = 0;
43352  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43353  it_nodes != sorted_nodes.end();
43354  it_nodes++)
43355  {
43356  polyline_vertices[counter].resize(2);
43357  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43358  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43359  counter++;
43360  }
43361 
43362  // Before going to the unrefinement or refinement process check that
43363  // all processors start from the same vertex. Start from the bottom
43364  // left vertex
43365  if (polyline_vertices[nvertex - 1][1] < polyline_vertices[0][1])
43366  {
43367  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43368  }
43369  else if (polyline_vertices[nvertex - 1][1] == polyline_vertices[0][1])
43370  {
43371  if (polyline_vertices[nvertex - 1][0] < polyline_vertices[0][0])
43372  {
43373  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43374  }
43375  }
43376 
43377  // Create the polyline associated with this edge
43378  TriangleMeshPolyLine* new_polyline_pt =
43379  new TriangleMeshPolyLine(polyline_vertices, b);
43380 
43381  // Get the curve section representation
43382  TriangleMeshCurveSection* curve_section_pt = vector_polyline_pt[pp];
43383 
43384  // Copy the connection information from the old shared polyline
43385  // to the new one
43386  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43387 
43388  // Now update the polyline according to the new vertices but first
43389  // check if the object is allowed to delete the representation
43390  // or if it should be done by other object
43391  bool delete_it_on_destructor = false;
43392 
43393  // Establish the element as being deleted by the destructor of
43394  // the class
43395  std::set<TriangleMeshCurveSection*>::iterator it =
43396  this->Free_curve_section_pt.find(curve_section_pt);
43397 
43398  if (it != this->Free_curve_section_pt.end())
43399  {
43400  this->Free_curve_section_pt.erase(it);
43401  delete curve_section_pt;
43402  delete_it_on_destructor = true;
43403  }
43404 
43405  // Copy the new representation
43406  vector_polyline_pt[pp] = new_polyline_pt;
43407 
43408  // Get the new curve section representation
43409  TriangleMeshCurveSection* new_curve_section_pt = vector_polyline_pt[pp];
43410 
43411  // Update the Boundary - Polyline map
43412  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43413 
43414  if (delete_it_on_destructor)
43415  {
43416  this->Free_curve_section_pt.insert(new_curve_section_pt);
43417  }
43418 
43419  } // for (pp < npoly)
43420  }
43421 
43422  //===================================================================
43423  // \short Fill the boundary elements structures when dealing with
43424  // shared boundaries that overlap internal boundaries. Document the
43425  // number of elements on the shared boundaries that go to internal
43426  // boundaries
43427  //===================================================================
43428  template<class ELEMENT>
43430  ELEMENT>::fill_boundary_elements_and_nodes_for_internal_boundaries()
43431  {
43432  // Dummy file
43433  std::ofstream some_file;
43434  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43435  }
43436 
43437  //===================================================================
43438  // \short Fill the boundary elements structures when dealing with
43439  // shared boundaries that overlap internal boundaries
43440  //===================================================================
43441  template<class ELEMENT>
43444  std::ofstream& outfile)
43445  {
43446  // Get the number of processors
43447  const unsigned nproc = this->communicator_pt()->nproc();
43448  // Get the rank of the current processor
43449  unsigned my_rank = this->communicator_pt()->my_rank();
43450 
43451  // Temporal name for the shared boundary overlaps structure
43452  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43453  this->Shared_boundary_overlaps_internal_boundary;
43454 
43455  // Register the internal boundary elements that where found to be
43456  // overlapped by shared boundaries
43457  std::set<unsigned> internal_boundary_overlaped;
43458 
43459  // Document the number of elements and nodes associated to the
43460  // boundaries before filling elements and nodes
43461  if (outfile.is_open())
43462  {
43463  const unsigned nbound = this->nboundary();
43464  outfile << "Number of boundaries: " << nbound << "\n\n";
43465  outfile << "Number of elements and nodes associated to each "
43466  << "boundary before\nfilling elements and nodes\n\n";
43467  for (unsigned i = 0; i < nbound; i++)
43468  {
43469  outfile << "Boundary (" << i << ") Elements ("
43470  << this->nboundary_element(i) << ") "
43471  << "Nodes (" << this->nboundary_node(i) << ")\n";
43472  }
43473  }
43474 
43475  // Storage for the shared boundaries in this processor
43476  std::set<unsigned> shared_boundaries_in_this_processor;
43477 
43478  // Get the shared boundaries that this processor has with other
43479  // processors
43480  for (unsigned iproc = 0; iproc < nproc; iproc++)
43481  {
43482  // Work with other processors only
43483  if (iproc != my_rank)
43484  {
43485  // Get the number of boundaries shared with the "iproc"-th processor
43486  unsigned nshared_boundaries_with_iproc =
43487  this->nshared_boundaries(my_rank, iproc);
43488 
43489  if (nshared_boundaries_with_iproc > 0)
43490  {
43491  // Get the boundaries ids shared with "iproc"-th processor
43492  Vector<unsigned> bound_shared_with_iproc;
43493  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
43494 
43495  // Loop over shared boundaries with "iproc"-th processor
43496  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43497  {
43498  unsigned bnd_id = bound_shared_with_iproc[bs];
43499  shared_boundaries_in_this_processor.insert(bnd_id);
43500  }
43501  }
43502  }
43503  }
43504 
43505  // ------------------------------------------------------------------
43506  // Copy the boundary elements and nodes from the shared boundary to
43507  // the internal boundary it overlaps
43508  // ------------------------------------------------------------------
43509  // Go through the shared boundaries that overlap internal boundaries
43510  for (std::map<unsigned, unsigned>::iterator it =
43511  shd_bnd_over_int_bnd.begin();
43512  it != shd_bnd_over_int_bnd.end();
43513  it++)
43514  {
43515  // The shared boundary id that overlaps with an internal boundary
43516  const unsigned shd_bnd_id = (*it).first;
43517  // The internal boundary overlapped by the shared boundary
43518  const unsigned int_bnd_id = (*it).second;
43519 
43520  // Check if the shared boundary exist in this processor
43521  std::set<unsigned>::iterator it_set =
43522  shared_boundaries_in_this_processor.find(shd_bnd_id);
43523  if (it_set != shared_boundaries_in_this_processor.end())
43524  {
43525  internal_boundary_overlaped.insert(int_bnd_id);
43526 
43527  // -----------------------------------------------------------------
43528  // First work the nodes of the shared boundaries that should be
43529  // added to the internal boundaries
43530  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43531 
43532  // Document the number of nodes that will be passed to the internal
43533  // boundary from the current shared boundary
43534  if (outfile.is_open())
43535  {
43536  outfile << "\nPass info. from shared (" << shd_bnd_id
43537  << ") to internal (" << int_bnd_id << ")\n";
43538  outfile << "Number of shared boundary nodes: " << nbnd_node_shd_bnd
43539  << "\n";
43540  }
43541 
43542  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43543  {
43544  // Get the boundary node
43545  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43546  // Add the node to the internal boundary
43547  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43548  }
43549 
43550  // -----------------------------------------------------------------
43551  // Second work the boundary elements
43552  // Get the number of boundary elements that should be copied to the
43553  // internal boundary
43554  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43555 
43556  // Document the number of elements that will be passed to the
43557  // internal boundary from the current shared boundary
43558  if (outfile.is_open())
43559  {
43560  outfile << "Number of shared boundary elements: " << nbnd_ele_shd_bnd
43561  << "\n\n";
43562  }
43563 
43564  // Go through the boundary elements in the shrared boundary and add
43565  // them to the boundary elements of the internal boundary
43566  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43567  {
43568  // Get the boundary element
43569  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43570  // Add the element to the boundary elements storage of the
43571  // internal boundary
43572  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43573  // Get the face index of the boundary
43574  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43575  // Add the face index to the storage of the boundary
43576  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43577 
43578  } // for (ie < nbnd_ele_shd_bnd)
43579 
43580  // If there are regions we need to fill the storage for regions too
43581  const unsigned nregions = this->nregion();
43582  if (nregions > 1)
43583  {
43584  for (unsigned ir = 0; ir < nregions; ir++)
43585  {
43586  // Get the region attribute
43587  const unsigned region_id =
43588  static_cast<unsigned>(this->Region_attribute[ir]);
43589 
43590  // Loop over all elements on boundaries in region ir
43591  const unsigned nele_ir =
43592  this->nboundary_element_in_region(shd_bnd_id, region_id);
43593  for (unsigned ier = 0; ier < nele_ir; ier++)
43594  {
43595  // Get the boundary element in current region
43596  FiniteElement* bnd_ele_pt =
43597  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43598  // Add the boundary element to the internal boundary in the
43599  // region
43600  this->Boundary_region_element_pt[int_bnd_id][region_id].push_back(
43601  bnd_ele_pt);
43602 
43603  // Get the face index of the boundary
43604  int face_index = this->face_index_at_boundary_in_region(
43605  shd_bnd_id, region_id, ier);
43606  // Add the face index to the storage of the boundary region
43607  this->Face_index_region_at_boundary[int_bnd_id][region_id]
43608  .push_back(face_index);
43609 
43610  } // for (ier < nele_ir)
43611 
43612  } // for (ir < nregions)
43613 
43614  } // if (nregions > 1)
43615 
43616  } // if (the shared boundary appears in the current processor)
43617 
43618  } // for (loop over the shared bound that overlap an internal bound)
43619 
43620  // Document the number of elements and nodes associated to the
43621  // boundaries after filling elements and nodes
43622  if (outfile.is_open())
43623  {
43624  const unsigned nbound = this->nboundary();
43625  outfile << "Number of boundaries: " << nbound << "\n\n";
43626  outfile << "Number of elements and nodes associated to each "
43627  << "boundary after\nfilling elements and nodes\n\n";
43628  for (unsigned i = 0; i < nbound; i++)
43629  {
43630  outfile << "Boundary (" << i << ") Elements ("
43631  << this->nboundary_element(i) << ")"
43632  << " Nodes (" << this->nboundary_node(i) << ")\n";
43633  }
43634  }
43635 
43636  // ------------------------------------------------------------------
43637  // Finally, re-setup the boundary coordinates for the new nodes on
43638  // the overlaped internal boundaries
43639  // ------------------------------------------------------------------
43640  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43641  it != internal_boundary_overlaped.end();
43642  it++)
43643  {
43644  const unsigned overlaped_internal_bnd_id = (*it);
43645 
43646  // Re-setup boundary coordinates
43647  this->template setup_boundary_coordinates<ELEMENT>(
43648  overlaped_internal_bnd_id);
43649  }
43650  }
43651 
43652 #endif // #ifdef OOMPH_HAS_MPI
43653 
43654  //======================================================================
43655  /// Move the boundary nodes onto the boundary defined by the old mesh
43656  //======================================================================
43657  template<class ELEMENT>
43659  RefineableTriangleMesh<ELEMENT>*& new_mesh_pt, const unsigned& b)
43660  {
43661  // Quick return
43662  if (!Boundary_coordinate_exists[b])
43663  {
43664  return;
43665  }
43666 
43667  // Firstly we set the boundary coordinates of the new nodes
43668  // In case the mapping between the geometric object's intrinsic coordinate
43669  // and the arc-length coordinate is nonlinear. This is only an
43670  // approximation, but it will ensure that the nodes that were input to
43671  // triangle will retain exactly the same boundary coordinates and then
43672  // linear interpolation is used between those values for any newly created
43673  // nodes.
43674 
43675  // We need to get the boundary nodes from the boundary face
43676  // elements since the "multi_domain" methods add nodes to the
43677  // "Boundary_node_pt" structure which have no boundary coordinates
43678  // assigned
43679  std::set<Node*> tmp_boundary_node_pt;
43680  const unsigned nboundary_ele = this->nboundary_element(b);
43681  for (unsigned e = 0; e < nboundary_ele; e++)
43682  {
43683  // Get the boundary bulk element
43684  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43685 #ifdef OOMPH_HAS_MPI
43686  // Only work with nonhalo elements if the mesh is distributed
43687  if (!bulk_ele_pt->is_halo())
43688  {
43689 #endif
43690  // Get the face index
43691  int face_index = this->face_index_at_boundary(b, e);
43692  // Create the face element
43693  FiniteElement* face_ele_pt =
43694  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
43695 
43696  // Get the number of nodes on the face element
43697  const unsigned nnodes = face_ele_pt->nnode();
43698  for (unsigned i = 0; i < nnodes; i++)
43699  {
43700  // Get the nodes in the face elements
43701  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43702  // Add the nodes to the set of boundary nodes
43703  tmp_boundary_node_pt.insert(tmp_node_pt);
43704  } // for (i < nnodes)
43705 
43706  // Free the memory allocated for the face element
43707  delete face_ele_pt;
43708  face_ele_pt = 0;
43709 #ifdef OOMPH_HAS_MPI
43710  } // if (!bulk_ele_pt->is_halo())
43711 #endif
43712 
43713  } // for (e < nboundary_ele)
43714 
43715  // Get the number of boundary nodes
43716  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43717 
43718  // Quick return if there are no nodes
43719  if (n_boundary_node == 0)
43720  {
43721 #ifdef OOMPH_HAS_MPI
43722  // Check if we are working with a distributed mesh
43723  if (!this->is_mesh_distributed())
43724  {
43725 #endif
43726  return;
43727 #ifdef OOMPH_HAS_MPI
43728  }
43729  else // The mesh is distributed !!!
43730  {
43731  // Do not forget to participate in the communication
43732  Mesh* face_mesh_pt = new Mesh();
43733  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43734  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43735 
43736  // Delete the allocated memory for the geometric object and face mesh
43737  delete mesh_geom_obj_pt;
43738 
43739  // Flush the nodes from the face mesh to make sure we
43740  // don't delete them (the bulk mesh still needs them!)
43741  face_mesh_pt->flush_node_storage();
43742  delete face_mesh_pt;
43743  return;
43744  }
43745 #endif
43746  } // if (n_boundary_node==0)
43747 
43748  // Create a vector of existing boundary nodes with their boundary
43749  // coordinate as the first entry so that we can use standard sort algorithms
43750  Vector<double> node_coord(3);
43751  Vector<double> b_coord(1);
43752 
43753  Vector<Vector<double>> old_boundary_node(n_boundary_node);
43754  unsigned tmp_counter = 0;
43755  for (std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43756  it_node != tmp_boundary_node_pt.end();
43757  it_node++, tmp_counter++)
43758  {
43759  Node* nod_pt = (*it_node);
43760  nod_pt->get_coordinates_on_boundary(b, b_coord);
43761  node_coord[0] = b_coord[0];
43762  node_coord[1] = nod_pt->x(0);
43763  node_coord[2] = nod_pt->x(1);
43764  old_boundary_node[tmp_counter] = node_coord;
43765  } // for (it_node != tmp_boundary_node_pt.end())
43766 
43767  // Sort the vector
43768  std::sort(old_boundary_node.begin(), old_boundary_node.end());
43769 
43770  // Set up an equivalent ordered vector for the new nodes, based on the
43771  // current coordinate which is the scaled arc-length.
43772  // Also provide storage for the original node index,
43773  // the mapped coordinate and a flag to indicate whether the mapped
43774  // coordinate has been assigned.
43775  // Get the nodes on the boundary but consider to which segment (which
43776  // may appear in a distributed mesh) they belong
43777  Vector<Vector<Node*>> segment_nodes_pt;
43778 
43779 #ifdef OOMPH_HAS_MPI
43780  // Get the number of segments
43781  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43782 #else
43783  // The number of segments is one since the boundary is not split
43784  // over multiple processors
43785  const unsigned nsegments = 1;
43786 #endif // #ifdef OOMPH_HAS_MPI
43787 
43788 #ifdef OOMPH_HAS_MPI
43789  // Get the total number of nodes on the boundary
43790  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43791 
43792  // Check if we are working with a distributed mesh
43793  if (this->is_mesh_distributed())
43794  {
43795  // If that is the case we need to ensure that the new mesh has
43796  // nodes too, if that is not the case then return
43797  // Quick return if there are no nodes
43798  if (n_new_boundary_node == 0)
43799  {
43800  // Do not forget to participate in the communication
43801  Mesh* face_mesh_pt = new Mesh();
43802  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43803  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43804 
43805  // Delete the allocated memory for the geometric object and face mesh
43806  delete mesh_geom_obj_pt;
43807  // Flush the nodes from the face mesh to make sure we
43808  // don't delete them (the bulk mesh still needs them!)
43809  face_mesh_pt->flush_node_storage();
43810  delete face_mesh_pt;
43811  return;
43812  }
43813  }
43814 #endif // #ifdef OOMPH_HAS_MPI
43815 
43816  // Create a vector of boundary nodes that must be moved
43817  Vector<Vector<unsigned>> nodes_to_be_snapped(nsegments);
43818 
43819  // Go through all the segments to assign the snapped zeta coordinates
43820  // for the new nodes
43821  for (unsigned is = 0; is < nsegments; is++)
43822  {
43823 #ifdef OOMPH_HAS_MPI
43824  const unsigned n_new_boundary_segment_node =
43825  new_mesh_pt->nboundary_segment_node(b, is);
43826 #else
43827  const unsigned n_new_boundary_segment_node =
43828  new_mesh_pt->nboundary_node(b);
43829 #endif // #ifdef OOMPH_HAS_MPI
43830 
43831  Vector<Vector<double>> new_boundary_node(n_new_boundary_segment_node);
43832  // There will be six data associated with each node
43833  node_coord.resize(6, 0.0);
43834  for (unsigned n = 0; n < n_new_boundary_segment_node; n++)
43835  {
43836 #ifdef OOMPH_HAS_MPI
43837  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b, is, n);
43838 #else
43839  Node* nod_pt = new_mesh_pt->boundary_node_pt(b, n);
43840 #endif // #ifdef OOMPH_HAS_MPI
43841  nod_pt->get_coordinates_on_boundary(b, b_coord);
43842  node_coord[0] = b_coord[0];
43843  node_coord[1] = nod_pt->x(0);
43844  node_coord[2] = nod_pt->x(1);
43845  node_coord[3] = n;
43846  new_boundary_node[n] = node_coord;
43847  } // for (n < n_new_boundary_segment_node)
43848 
43849  // Sort the new boundary nodes based on their arc-length coordinate
43850  std::sort(new_boundary_node.begin(), new_boundary_node.end());
43851 
43852  // We now have two sets of nodes ordered by a coordinate that acts in the
43853  // same direction and has the same limits.
43854 
43855  // Loop over the vector of new nodes and allocate exactly the same
43856  // coordinate as the old nodes at points of coincidence
43857  unsigned old_index = 0;
43858  for (unsigned n = 0; n < n_new_boundary_segment_node; ++n)
43859  {
43860  // Loop over the set of old nodes and if the x and y coordinates
43861  // coincide with the new node copy accross the new boundary coordinate
43862  for (unsigned m = old_index; m < n_boundary_node; ++m)
43863  {
43864  if ((std::fabs(old_boundary_node[m][1] - new_boundary_node[n][1]) <
43865  1.0e-14) &&
43866  (std::fabs(old_boundary_node[m][2] - new_boundary_node[n][2]) <
43867  1.0e-14))
43868  {
43869  // Store the boundary coordinate from the old mesh
43870  new_boundary_node[n][4] = old_boundary_node[m][0];
43871  // Say that it has been stored
43872  new_boundary_node[n][5] = 1.0;
43873  // For efficiency, we can start the iteration from here next
43874  // time round because both vectors are ordered
43875  old_index = m;
43876  break;
43877  }
43878  }
43879  }
43880 
43881  // Check that the end-points have new boundary coordinates allocated
43882 #ifdef PARANOID
43883  if ((new_boundary_node[0][5] == 0.0) ||
43884  (new_boundary_node[n_new_boundary_segment_node - 1][5] == 0.0))
43885  {
43886  std::ostringstream error_stream;
43887  error_stream
43888  << "New boundary coordinates not found for the first and/or last "
43889  << "nodes\n"
43890  << "on the boundary " << b << ". This should not happen because "
43891  << "these\nlimits should have been setup in the constructor\n";
43892  error_stream
43893  << "The distance between the new and old nodes is probably outside\n"
43894  << "our tolerance.\n";
43895  error_stream.precision(20);
43896  error_stream << "Old boundaries: \n";
43897  error_stream << old_boundary_node[0][1] << " "
43898  << old_boundary_node[0][2] << " : "
43899  << old_boundary_node[n_boundary_node - 1][1] << " "
43900  << old_boundary_node[n_boundary_node - 1][2] << "\n";
43901  error_stream << "New boundaries: \n"
43902  << new_boundary_node[0][1] << " "
43903  << new_boundary_node[0][2] << " : "
43904  << new_boundary_node[n_new_boundary_segment_node - 1][1]
43905  << " "
43906  << new_boundary_node[n_new_boundary_segment_node - 1][2]
43907  << "\n";
43908  OomphLibWarning(error_stream.str(),
43909  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43910  OOMPH_EXCEPTION_LOCATION);
43911  }
43912 #endif
43913 
43914  // This is only true if the boundary is not splitted among the
43915  // processors
43916  if (!this->is_mesh_distributed())
43917  {
43918  // The end points should always be present, so we
43919  // can (and must) always add them in exactly
43920  new_boundary_node[0][4] = new_boundary_node[0][0];
43921 
43922  /// Correct!? Because assigned again below
43923  new_boundary_node[n_new_boundary_segment_node - 1][4] =
43924  new_boundary_node[0][5] = 1.0;
43925 
43926  new_boundary_node[n_new_boundary_segment_node - 1][4] =
43927  new_boundary_node[n_new_boundary_segment_node - 1][0];
43928  new_boundary_node[n_new_boundary_segment_node - 1][5] = 1.0;
43929  }
43930 
43931  // Now loop over the interior nodes again and
43932  // use linear interpolation to fill in any unassigned coordiantes
43933  for (unsigned n = 1; n < n_new_boundary_segment_node - 1; ++n)
43934  {
43935  // If the new boundary coordinate has NOT been allocated
43936  if (new_boundary_node[n][5] == 0.0)
43937  {
43938  // Add its (unsorted) node number to the list
43939  nodes_to_be_snapped[is].push_back(
43940  static_cast<unsigned>(new_boundary_node[n][3]));
43941 
43942  // We assume that the previous nodal value has been assigned
43943  // and read out the old and new boundary coordinates
43944  double zeta_old_low = new_boundary_node[n - 1][0];
43945  double zeta_new_low = new_boundary_node[n - 1][4];
43946 
43947  // Loop over the nodes above the current node until
43948  // we find the next one that has been allocated
43949  for (unsigned m = n + 1; m < n_new_boundary_segment_node; ++m)
43950  {
43951  if (new_boundary_node[m][5] == 1.0)
43952  {
43953  // Read out the old boundary coordinate
43954  double zeta_old_high = new_boundary_node[m][0];
43955  double zeta_new_high = new_boundary_node[m][4];
43956  // Use linear interpolation to assign the new boundary coordinate
43957  double frac = (new_boundary_node[n][0] - zeta_old_low) /
43958  (zeta_old_high - zeta_old_low);
43959  new_boundary_node[n][4] =
43960  zeta_new_low + frac * (zeta_new_high - zeta_new_low);
43961  new_boundary_node[n][5] = 1.0;
43962  break;
43963  }
43964  }
43965  }
43966  }
43967 
43968  // Loop over all the nodes and set the new boundary coordinate
43969  for (unsigned n = 0; n < n_new_boundary_segment_node; ++n)
43970  {
43971  if (new_boundary_node[n][5] == 0)
43972  {
43973  throw OomphLibError(
43974  "New boundary coordinate not assigned\n",
43975  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43976  OOMPH_EXCEPTION_LOCATION);
43977  }
43978 
43979 #ifdef OOMPH_HAS_MPI
43980  // get the old coordinate
43981  new_mesh_pt
43983  b, is, static_cast<unsigned>(new_boundary_node[n][3]))
43984  ->get_coordinates_on_boundary(b, b_coord);
43985  // Set the new coordinate
43986  b_coord[0] = new_boundary_node[n][4];
43987  new_mesh_pt
43989  b, is, static_cast<unsigned>(new_boundary_node[n][3]))
43990  ->set_coordinates_on_boundary(b, b_coord);
43991 #else
43992  // get the old coordinate
43993  new_mesh_pt
43994  ->boundary_node_pt(b, static_cast<unsigned>(new_boundary_node[n][3]))
43995  ->get_coordinates_on_boundary(b, b_coord);
43996  // Set the new coordinate
43997  b_coord[0] = new_boundary_node[n][4];
43998  new_mesh_pt
43999  ->boundary_node_pt(b, static_cast<unsigned>(new_boundary_node[n][3]))
44000  ->set_coordinates_on_boundary(b, b_coord);
44001 #endif // #ifdef OOMPH_HAS_MPI
44002  }
44003 
44004  } // for (is < nsegments)
44005 
44006  Mesh* face_mesh_pt = new Mesh();
44007  create_unsorted_face_mesh_representation(b, face_mesh_pt);
44008 
44009  // Now that the coordinates have been set up we can do the snapping
44010  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
44011 
44012  // Now assign the new nodes positions based on the old meshes
44013  // potentially curvilinear boundary (its geom object incarnation)
44014  Vector<double> new_x(2);
44015 
44016  // Loop over the nodes that need to be snapped
44017  for (unsigned is = 0; is < nsegments; is++)
44018  {
44019  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
44020 
44021  for (unsigned in = 0; in < nnodes_to_snap; in++)
44022  {
44023  // Read out the boundary node number
44024  unsigned n = nodes_to_be_snapped[is][in];
44025 #ifdef OOMPH_HAS_MPI
44026  // Get the boundary coordinate of all new nodes
44027  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b, is, n);
44028 #else
44029  // Get the boundary coordinate of all new nodes
44030  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b, n);
44031 #endif // #ifdef OOMPH_HAS_MPI
44032 
44033  nod_pt->get_coordinates_on_boundary(b, b_coord);
44034  // Let's find boundary coordinates of the new node
44035  mesh_geom_obj_pt->position(b_coord, new_x);
44036 
44037  // Now snap to the boundary
44038  for (unsigned i = 0; i < 2; i++)
44039  {
44040  nod_pt->x(i) = new_x[i];
44041  }
44042  }
44043  }
44044 
44045  // Delete the allocated memory for the geometric object and face mesh
44046  delete mesh_geom_obj_pt;
44047  // Flush the nodes from the face mesh to make sure we
44048  // don't delete them (the bulk mesh still needs them!)
44049  face_mesh_pt->flush_node_storage();
44050  delete face_mesh_pt;
44051 
44052  // Fix up the elements adjacent to the boundary
44053 
44054  // Dummy six node element for sorting out bubble node for
44055  // seven node enriched quadratic triangles
44056  TElement<2, 3> dummy_six_node_element;
44057  for (unsigned j = 0; j < 6; j++)
44058  {
44059  dummy_six_node_element.construct_node(j);
44060  }
44061 
44062  // This should definitely become a triangular element member function
44063  // Loop over elements
44064  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
44065  for (unsigned e = 0; e < n_bound_el; e++)
44066  {
44067  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b, e);
44068 
44069  // Deal with different numbers of nodes separately
44070  unsigned nnod = el_pt->nnode();
44071 
44072  // #ifdef PARANOID
44073  // // Flag to indicate if we successully classified/dealt with the
44074  // element bool success=false;
44075  // #endif
44076 
44077  // Simplex element: Nothing to be done other than error checking
44078  if (nnod == 3)
44079  {
44080 #ifdef PARANOID
44081  // Try to cast to a simplex element
44082  TElement<2, 2>* t_el_pt = dynamic_cast<TElement<2, 2>*>(el_pt);
44083  if (t_el_pt == 0)
44084  {
44085  throw OomphLibError(
44086  "Have a three-noded element that's not a TElement<2,2>",
44087  OOMPH_CURRENT_FUNCTION,
44088  OOMPH_EXCEPTION_LOCATION);
44089  }
44090  // If I get there I must not have thrown :)
44091  // success=true;
44092 #endif
44093  }
44094  // Quadratic element (or enriched quadratic)
44095 
44096  else if ((nnod == 6) || (nnod == 7))
44097  {
44098 #ifdef PARANOID
44099  // Try to cast to a quadratic element
44100  TElement<2, 3>* t_el_pt = dynamic_cast<TElement<2, 3>*>(el_pt);
44101  if (t_el_pt == 0)
44102  {
44103  if (nnod == 6)
44104  {
44105  throw OomphLibError(
44106  "Have a six-noded element that's not a TElement<2,3>",
44107  OOMPH_CURRENT_FUNCTION,
44108  OOMPH_EXCEPTION_LOCATION);
44109  }
44110  else
44111  {
44112  throw OomphLibError(
44113  "Have a seven-noded element that's not a TElement<2,3>",
44114  OOMPH_CURRENT_FUNCTION,
44115  OOMPH_EXCEPTION_LOCATION);
44116  }
44117  }
44118  // If I get there I must not have thrown :)
44119  // success=true;
44120 #endif
44121  // Deal with six noded stuff for all (normal and enriched) elements
44122 
44123  ///----------------------------------------------------------------
44124  /// Repositioning of mid-side nodes
44125  ///----------------------------------------------------------------
44126 
44127  // Side between 0 and 1
44128  if (el_pt->node_pt(3)->is_on_boundary(b))
44129  {
44130  // Make sure that the node I'm about to move is NOT on
44131  // a boundary
44132  if (!el_pt->node_pt(5)->is_on_boundary())
44133  {
44134  // Reset the internal nodes
44135  for (unsigned i = 0; i < 2; i++)
44136  {
44137  el_pt->node_pt(5)->x(i) =
44138  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
44139  }
44140  }
44141  // Make sure that the node I'm about to move is NOT on
44142  // a boundary
44143  if (!el_pt->node_pt(4)->is_on_boundary())
44144  {
44145  // Reset the internal nodes
44146  for (unsigned i = 0; i < 2; i++)
44147  {
44148  el_pt->node_pt(4)->x(i) =
44149  0.5 * (el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
44150  }
44151  }
44152  }
44153 
44154  // Side between 1 and 2
44155  if (el_pt->node_pt(4)->is_on_boundary(b))
44156  {
44157  // Make sure that the node I'm about to move is NOT on
44158  // a boundary
44159  if (!el_pt->node_pt(5)->is_on_boundary())
44160  {
44161  // Reset the internal nodes
44162  for (unsigned i = 0; i < 2; i++)
44163  {
44164  el_pt->node_pt(5)->x(i) =
44165  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
44166  }
44167  }
44168  // Make sure that the node I'm about to move is NOT on
44169  // a boundary
44170  if (!el_pt->node_pt(3)->is_on_boundary())
44171  {
44172  // Reset the internal nodes
44173  for (unsigned i = 0; i < 2; i++)
44174  {
44175  el_pt->node_pt(3)->x(i) =
44176  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
44177  }
44178  }
44179  }
44180 
44181  // Side between 0 and 2
44182  if (el_pt->node_pt(5)->is_on_boundary(b))
44183  {
44184  // Make sure that the node I'm about to move is NOT on
44185  // a boundary
44186  if (!el_pt->node_pt(4)->is_on_boundary())
44187  {
44188  // Reset the internal nodes
44189  for (unsigned i = 0; i < 2; i++)
44190  {
44191  el_pt->node_pt(4)->x(i) =
44192  0.5 * (el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
44193  }
44194  }
44195  // Make sure that the node I'm about to move is NOT on
44196  // a boundary
44197  if (!el_pt->node_pt(3)->is_on_boundary())
44198  {
44199  // Reset the internal nodes
44200  for (unsigned i = 0; i < 2; i++)
44201  {
44202  el_pt->node_pt(3)->x(i) =
44203  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
44204  }
44205  }
44206  }
44207 
44208  // If it's seven noded it's likely to be an enriched one: Deal with
44209  // the central (bubble) node
44210  if (nnod == 7)
44211  {
44212  // Try to cast to an enriched quadratic element
44213  TBubbleEnrichedElement<2, 3>* t_el_pt =
44214  dynamic_cast<TBubbleEnrichedElement<2, 3>*>(el_pt);
44215  if (t_el_pt == 0)
44216  {
44217  throw OomphLibError("Have seven-noded element that's not a "
44218  "TBubbleEnrichedElement<2,3>",
44219  OOMPH_CURRENT_FUNCTION,
44220  OOMPH_EXCEPTION_LOCATION);
44221  }
44222 
44223  // Assign the new non-bubble coordinates to the six noded dummy
44224  // element
44225  for (unsigned j = 0; j < 6; j++)
44226  {
44227  for (unsigned i = 0; i < 2; i++)
44228  {
44229  dummy_six_node_element.node_pt(j)->x(i) = el_pt->node_pt(j)->x(i);
44230  }
44231  }
44232 
44233  // Local coordinate of enriched node
44234  unsigned j_enriched = 6;
44235  Vector<double> s(2);
44236  el_pt->local_coordinate_of_node(j_enriched, s);
44237 
44238  // Get its position from non-enriched element
44239  Vector<double> x(2);
44240  dummy_six_node_element.interpolated_x(s, x);
44241  el_pt->node_pt(j_enriched)->x(0) = x[0];
44242  el_pt->node_pt(j_enriched)->x(1) = x[1];
44243  }
44244  }
44245  // Any other case cannot be dealt with at the moment
44246 
44247  else
44248  {
44249  std::ostringstream error_stream;
44250  error_stream << "Cannot deal with this particular " << nnod
44251  << "-noded element yet.\n"
44252  << "Please implement this yourself.\n";
44253  throw OomphLibError(
44254  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
44255  }
44256  }
44257 
44258  // Cleanup
44259  for (unsigned j = 0; j < 6; j++)
44260  {
44261  delete dummy_six_node_element.node_pt(j);
44262  }
44263  }
44264 
44265 
44266 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
44267 
44268 } // namespace oomph
44269 
44270 #endif
oomph::RefineableTriangleMesh::update_open_curve_using_elements_area
bool update_open_curve_using_elements_area(TriangleMeshOpenCurve *&open_curve_pt, const Vector< double > &target_area)
Updates the open curve but using the elements area instead of the default refinement and unrefinement...
Definition: triangle_mesh.template.cc:38620
oomph::RefineableTriangleMesh::create_polylines_from_polyfiles
void create_polylines_from_polyfiles(const std::string &node_file_name, const std::string &poly_file_name)
Helper function to create polylines and fill associate data.
Definition: triangle_mesh.template.cc:36642
oomph::TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values
void compute_boundary_segments_connectivity_and_initial_zeta_values(const unsigned &b)
Compute the boundary segments connectivity for those boundaries that were splited during the distribu...
Definition: triangle_mesh.template.cc:1838
oomph::TriangleMesh::select_boundary_face_elements
void select_boundary_face_elements(Vector< FiniteElement * > &face_el_pt, const unsigned &b, bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Select face element from boundary using the criteria to decide which of the two face elements should ...
Definition: triangle_mesh.template.cc:5281
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme
void reset_halo_haloed_scheme()
In charge of. re-establish the halo(ed) scheme on all processors. Sends info. to create halo elements...
Definition: triangle_mesh.template.cc:15486
oomph::classcomp::Tol
static double Tol
Definition: triangle_mesh.template.cc:15201
oomph::RefineableTriangleMesh::restore_polyline_connections_helper
void restore_polyline_connections_helper(TriangleMeshPolyLine *polyline_pt, Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Restore the connections of the specific polyline The vertices numbering on the destination boundaries...
Definition: triangle_mesh.template.cc:33295
oomph::RefineableTriangleMesh::sort_nodes_on_shared_boundaries
void sort_nodes_on_shared_boundaries()
Sort the nodes on shared boundaries so that the processors that share a boundary agree with the order...
Definition: triangle_mesh.template.cc:15292
oomph::RefineableTriangleMesh::update_open_curve_after_restart
void update_open_curve_after_restart(TriangleMeshOpenCurve *&open_curve_pt)
Updates the open curve representation after restart.
Definition: triangle_mesh.template.cc:42038
oomph::RefineableTriangleMesh::update_shared_curve_using_elements_area
bool update_shared_curve_using_elements_area(Vector< TriangleMeshPolyLine * > &vector_polyline_pt, const Vector< double > &target_areas)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:39895
oomph::TriangleMeshParameters::internal_open_curves_pt
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
Definition: triangle_mesh.template.h:176
oomph::RefineableTriangleMesh::get_boundary_segment_nodes_helper
void get_boundary_segment_nodes_helper(const unsigned &b, Vector< Vector< Node * >> &tmp_segment_nodes)
Get the nodes on the boundary (b), these are stored in the segment they belong (also used by the load...
Definition: triangle_mesh.template.cc:29072
oomph::RefineableTriangleMesh::unrefine_boundary_constrained_by_target_area
bool unrefine_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double >> &vector_bnd_vertices, double &unrefinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40560
oomph::RefineableTriangleMesh::snap_nodes_onto_boundary
void snap_nodes_onto_boundary(RefineableTriangleMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
Definition: triangle_mesh.template.cc:43658
oomph::TriangleMeshParameters::internal_closed_curve_pt
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
Definition: triangle_mesh.template.h:163
oomph::TriangleMesh::create_polylines_from_halo_elements_helper
void create_polylines_from_halo_elements_helper(const Vector< unsigned > &element_domain, std::map< GeneralisedElement *, unsigned > &element_to_global_index, std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< Vector< GeneralisedElement * >>> &input_halo_elements, std::map< std::pair< Node *, Node * >, unsigned > &elements_edges_on_boundary, Vector< Vector< Vector< TriangleMeshPolyLine * >>> &output_polylines_pt)
Creates polylines from the intersection of halo elements on all processors. The new polylines define ...
Definition: triangle_mesh.template.cc:11770
oomph::TriangleMesh::update_holes_information_helper
void update_holes_information_helper(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< Vector< double >> &output_holes_coordinates)
Keeps those vertices that define a hole, those that are inside closed internal boundaries in the new ...
Definition: triangle_mesh.template.cc:10928
oomph::TriangleMesh::break_loops_on_shared_polyline_helper
void break_loops_on_shared_polyline_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * >> &output_sorted_nodes_pt, Vector< Vector< FiniteElement * >> &output_boundary_element_pt, Vector< Vector< int >> &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:13265
oomph::TriangleMesh::create_tmp_open_curves_helper
void create_tmp_open_curves_helper(Vector< Vector< TriangleMeshPolyLine * >> &sorted_open_curves_pt, Vector< TriangleMeshPolyLine * > &unsorted_shared_to_internal_poly_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Take the polylines from the original open curves and created new temporaly representations of open cu...
Definition: triangle_mesh.template.cc:9031
oomph::RefineableTriangleMesh::refine_boundary_constrained_by_target_area
bool refine_boundary_constrained_by_target_area(MeshAsGeomObject *mesh_geom_obj_pt, Vector< Vector< double >> &vector_bnd_vertices, double &refinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40816
oomph::RefineableTriangleMesh::fill_boundary_elements_and_nodes_for_internal_boundaries
void fill_boundary_elements_and_nodes_for_internal_boundaries()
Definition: triangle_mesh.template.cc:43430
oomph::RefineableTriangleMesh::max_element_size
double & max_element_size()
Max element size allowed during adaptation.
Definition: triangle_mesh.template.h:2483
oomph::RefineableTriangleMesh::add_element_load_balance_helper
void add_element_load_balance_helper(const unsigned &iproc, Vector< Vector< std::map< unsigned, FiniteElement * >>> &received_old_haloed_element_pt, FiniteElement *ele_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27584
oomph::RefineableTriangleMesh::load_balance
void load_balance(const Vector< unsigned > &input_target_domain_for_local_non_halo_element)
Performs the load balancing for unstructured meshes, the load balancing strategy is based on mesh mig...
Definition: triangle_mesh.template.cc:20451
oomph::RefineableTriangleMesh::reset_shared_boundary_elements_and_nodes
void reset_shared_boundary_elements_and_nodes(const bool flush_elements=true, const bool update_elements=true, const bool flush_nodes=true, const bool update_nodes=true)
Re-establish the shared boundary elements after the adaptation process (the updating of shared nodes ...
Definition: triangle_mesh.template.cc:15403
triangle_mesh.template.h
oomph::RefineableTriangleMesh::min_permitted_angle
double & min_permitted_angle()
Min angle before remesh gets triggered.
Definition: triangle_mesh.template.h:2495
oomph::TriangleMesh::break_loops_on_shared_polyline_load_balance_helper
void break_loops_on_shared_polyline_load_balance_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< FiniteElement * > &input_boundary_face_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * >> &output_sorted_nodes_pt, Vector< Vector< FiniteElement * >> &output_boundary_element_pt, Vector< Vector< FiniteElement * >> &output_boundary_face_element_pt, Vector< Vector< int >> &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:14190
oomph::TriangleMeshParameters::disable_automatic_creation_of_vertices_on_boundaries
void disable_automatic_creation_of_vertices_on_boundaries()
Definition: triangle_mesh.template.h:354
oomph::RefineableTriangleMesh::add_non_delete_vertices_from_boundary_helper
void add_non_delete_vertices_from_boundary_helper(Vector< Vector< Node * >> src_bound_segment_node_pt, Vector< Vector< Node * >> dst_bound_segment_node_pt, const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
Adds the vertices from the sources boundary that are repeated in the destination boundary to the list...
Definition: triangle_mesh.template.cc:32588
oomph::TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values
void identify_boundary_segments_and_assign_initial_zeta_values(const unsigned &b, Vector< FiniteElement * > &input_face_ele_pt, const bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Identify the segments from the old mesh (original mesh) in the new mesh (this) and assign initial and...
oomph::RefineableTriangleMesh::refine_shared_boundary_constrained_by_target_area
bool refine_shared_boundary_constrained_by_target_area(Vector< Vector< double >> &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:41167
oomph::RefineableTriangleMesh::add_halo_node_helper
void add_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add halo node.
Definition: triangle_mesh.template.cc:19360
t
t_0 \f$ and \f$ t=t_0+\Delta t \f$. At \f$ t=t_0+2 \Delta t \f$, the automatic mesh adaptation splits one of the fluid elements, creating the five new \c Nodes, shown in red(for simplicity we only show the fluid elements' vertex nodes). Their position is determined by the father element 's \c MacroElement mapping, using the current position of the \c MeshAsGeomObject, obtained from the interpolation between the nodal positions of its \c SolidNodes(shown as green circles). @I w 0.75\textwidth history_values "Sketch illustrating the assignment of positional history values for newly-created nodes in FSI problems. The positional history values of the newly-created Nodes (shown in red) are given by the positions they would have had if they had already existed at previous timesteps. " So far, so good! A subtle problem arises when we try to assign the positional history values for the newly-created \c Nodes. The evaluation of the \c MacroElement mapping at the previous timesteps(required to determine the positions the newly-created \c Nodes would have had, if they had already existed at previous timesteps) requires access to the previous wall shapes. In< A HREF="../../../navier_stokes/collapsible_channel/html/index.html"> the non-FSI problem discussed earlier</A >, the wall shape was given analytically and could therefore be evaluated at arbitrary times. In the FSI problem considered here, the previous wall shape is not available as the previous positions of the \c SolidNodes are not required(and are therefore not stored) for the solution of the(steady!) wall equations.< HR > \subsection soln The solution:The Steady< NSTEPS > timestepper The solution to the problem is simple:Recall that the final entry in the argument list of \c oomph-lib 's mesh constructors specifies the \c TimeStepper to be used for the evaluation of any time-derivatives. The \c TimeStepper 's member function \c TimeStepper::ntstorage() specifies the total number of values(the current value plus the number of history values) required to evaluate the time-derivatives t
Definition: fsi_collapsible_channel_adapt.txt:100
oomph::TriangleMesh::sort_polylines_helper
void sort_polylines_helper(Vector< TriangleMeshPolyLine * > &unsorted_polylines_pt, Vector< Vector< TriangleMeshPolyLine * >> &sorted_polylines_pt)
Sorts the polylines so they be continuous and then we can create a closed or open curve from them.
Definition: triangle_mesh.template.cc:11338
oomph::RefineableTriangleMesh::add_halo_element_helper
void add_halo_element_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:19199
TimeStepper
it is used by the c we always provide a default argument for the pointer to the c TimeStepper a pointer to static a instantiation of c oomph lib s dummy c TimeStepper
Definition: fsi_collapsible_channel_adapt.txt:106
oomph::RefineableTriangleMesh::add_haloed_node_helper
void add_haloed_node_helper(unsigned &iproc, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:18903
oomph::TriangleMeshParameters::set_communicator_pt
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
Definition: triangle_mesh.template.h:304
oomph::TriangleMesh::create_shared_polyline
void create_shared_polyline(const unsigned &my_rank, const unsigned &shd_bnd_id, const unsigned &iproc, const unsigned &jproc, std::list< Node * > &sorted_nodes, const int &root_edge_bnd_id, Vector< FiniteElement * > &bulk_bnd_ele_pt, Vector< int > &face_index_ele, Vector< Vector< TriangleMeshPolyLine * >> &unsorted_polylines_pt, const int &connect_to_the_left_flag, const int &connect_to_the_right_flag)
Create the shared polyline and fill the data structured that keep all the information associated with...
Definition: triangle_mesh.template.cc:14617
oomph::RefineableTriangleMesh::apply_max_length_constraint
bool apply_max_length_constraint(Mesh *face_mesh_pt, Vector< Vector< double >> &vector_bnd_vertices, double &max_length_constraint)
Definition: triangle_mesh.template.cc:35554
oomph::TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary
void re_scale_re_assigned_initial_zeta_values_for_internal_boundary(const unsigned &b)
Re-scale the re-assigned zeta values for the boundary nodes, apply only for internal boundaries.
Definition: triangle_mesh.template.cc:6564
oomph::RefineableTriangleMesh::update_polygon_after_restart
void update_polygon_after_restart(TriangleMeshPolygon *&polygon_pt)
Updates the polylines representation after restart.
Definition: triangle_mesh.template.cc:41269
oomph::RefineableTriangleMesh::update_open_curve_using_face_mesh
bool update_open_curve_using_face_mesh(TriangleMeshOpenCurve *open_polyline_pt, const bool &check_only=false)
Helper function that updates the input open curve by using end-points of elements from FaceMesh(es) t...
Definition: triangle_mesh.template.cc:34629
oomph::RefineableTriangleMesh::refine_boundary
bool refine_boundary(Mesh *face_mesh_pt, Vector< Vector< double >> &vector_bnd_vertices, double &refinement_tolerance, const bool &check_only=false)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:35408
oomph::RefineableTriangleMesh::create_temporary_boundary_connections
void create_temporary_boundary_connections(Vector< TriangleMeshPolygon * > &tmp_outer_polygons_pt, Vector< TriangleMeshOpenCurve * > &tmp_open_curves_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the temporary r...
Definition: triangle_mesh.template.cc:33050
oomph::TriangleMesh::boundary_segment_node_pt
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
Definition: triangle_mesh.template.h:958
oomph::RefineableTriangleMesh::send_and_receive_elements_nodes_info
void send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
Helper function to send back halo and haloed information.
Definition: triangle_mesh.template.cc:18955
oomph::TriangleMesh::get_element_edges_on_boundary
void get_element_edges_on_boundary(std::map< std::pair< Node *, Node * >, unsigned > &element_edges_on_boundary)
Get the element edges (pair of nodes, edges) that lie on a boundary (used to mark shared boundaries t...
Definition: triangle_mesh.template.cc:11705
oomph::TriangleMesh::Point::x
coord_t x
Definition: triangle_mesh.template.h:2193
oomph::RefineableTriangleMesh::adapt
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
Definition: triangle_mesh.template.cc:29595
oomph::RefineableTriangleMesh::compute_shared_node_degree_helper
void compute_shared_node_degree_helper(Vector< Vector< FiniteElement * >> &unsorted_face_ele_pt, std::map< Node *, unsigned > &global_node_degree)
Computes the degree of the nodes on the shared boundaries, the degree of the node is computed from th...
Definition: triangle_mesh.template.cc:24845
oomph::TriangleMesh::Point::y
coord_t y
Definition: triangle_mesh.template.h:2193
oomph::RefineableTriangleMesh::send_boundary_node_info_of_shared_nodes
void send_boundary_node_info_of_shared_nodes(Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Get the original boundaries to which is associated each shared node, and send the info....
Definition: triangle_mesh.template.cc:17056
oomph::TriangleMesh::create_tmp_polygons_helper
void create_tmp_polygons_helper(Vector< Vector< TriangleMeshPolyLine * >> &polylines_pt, Vector< TriangleMeshPolygon * > &polygons_pt)
Take the polylines from the shared boundaries and create temporary polygon representations of the dom...
Definition: triangle_mesh.template.cc:8631
oomph::TriangleMesh::output_boundary_coordinates
void output_boundary_coordinates(const unsigned &b, std::ostream &outfile)
Definition: triangle_mesh.template.cc:8014
oomph::RefineableTriangleMesh::create_sorted_face_mesh_representation
void create_sorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt, std::map< FiniteElement *, bool > &is_inverted, bool &inverted_face_mesh)
Helper function Creates a sorted face mesh representation of the specified PolyLine It means that the...
Definition: triangle_mesh.template.cc:35705
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition: triangle_mesh.template.h:2253
oomph::RefineableTriangleMesh::resume_boundary_connections
void resume_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Resume the boundary connections that may have been suspended because the destination boundary is no p...
Definition: triangle_mesh.template.cc:34048
oomph::RefineableTriangleMesh::min_element_size
double & min_element_size()
Min element size allowed during adaptation.
Definition: triangle_mesh.template.h:2489
oomph::RefineableTriangleMesh::create_halo_element
void create_halo_element(unsigned &iproc, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:19111
oomph::RefineableTriangleMesh::add_received_node_load_balance_helper
void add_received_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * >> &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * >>> &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add a new node from load balance.
Definition: triangle_mesh.template.cc:27841
oomph::RefineableTriangleMesh::unrefine_boundary
bool unrefine_boundary(const unsigned &b, const unsigned &c, Vector< Vector< double >> &vector_bnd_vertices, double &unrefinement_tolerance, const bool &check_only=false)
Helper function that performs the unrefinement process.
Definition: triangle_mesh.template.cc:35113
AlgebraicMesh
this is used if there is only a single node update as in the c AlgebraicCollapsibleChannelMesh n n A vector such as the intrinsic coordinates of reference points on the c GeomObjects n n By we assume that a newly created c AlgebraicNode is updated by the same node update function as the c AlgebraicNodes in its father element Therefore we pass the pointer to the c AlgebraicMesh
Definition: fsi_collapsible_channel_adapt.txt:199
oomph::TriangleMeshParameters::regions_coordinates
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
Definition: triangle_mesh.template.h:255
oomph::TriangleMesh::dump_distributed_info_for_restart
void dump_distributed_info_for_restart(std::ostream &dump_file)
Used to dump info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7436
oomph::RefineableTriangleMesh::get_required_nodal_information_load_balance_helper
void get_required_nodal_information_load_balance_helper(Vector< Vector< FiniteElement * >> &f_halo_ele_pt, unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from an haloed node so that a fully-functional ...
Definition: triangle_mesh.template.cc:26810
oomph::TriangleMeshParameters
Helper object for dealing with the parameters used for the TriangleMesh objects.
Definition: triangle_mesh.template.h:93
oomph::RefineableTriangleMesh::update_polygon_using_face_mesh
bool update_polygon_using_face_mesh(TriangleMeshPolygon *polygon_pt, const bool &check_only=false)
Helper function that updates the input polygon's PSLG by using the end-points of elements from FaceMe...
Definition: triangle_mesh.template.cc:34138
oomph::RefineableTriangleMesh::update_other_proc_shd_bnd_node_helper
void update_other_proc_shd_bnd_node_helper(Node *&new_nod_pt, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, Vector< unsigned > &other_processor_1, Vector< unsigned > &other_processor_2, Vector< unsigned > &other_shared_boundaries, Vector< unsigned > &other_indexes, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function that assigns/updates the references to the node so that it can be found with any othe...
Definition: triangle_mesh.template.cc:20302
oomph::TriangleMesh::build_from_scaffold
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
Definition: triangle_mesh.template.cc:44
oomph::TriangleMesh::shared_boundary_overlaps_internal_boundary
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
Definition: triangle_mesh.template.h:1762
oomph::TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary
void re_assign_initial_zeta_values_for_internal_boundary(const unsigned &b, Vector< std::list< FiniteElement * >> &old_segment_sorted_ele_pt, std::map< FiniteElement *, bool > &old_is_inverted)
Re-assign the boundary segments initial zeta (arclength) value for those internal boundaries that wer...
Definition: triangle_mesh.template.cc:4089
oomph::RefineableTriangleMesh::add_node_load_balance_helper
void add_node_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * >> &f_halo_ele_pt, Vector< Node * > &new_nodes_on_domain, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:26752
oomph::RefineableSolidTriangleMesh
Unstructured refineable Triangle Mesh upgraded to solid mesh.
Definition: triangle_mesh.template.h:3951
oomph::RefineableTriangleMesh::compute_global_node_names_and_shared_nodes
void compute_global_node_names_and_shared_nodes(Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Compute the names of the nodes on shared boundaries in this (my_rank) processor with other processors...
Definition: triangle_mesh.template.cc:16061
oomph::TriangleMesh::oomph_vertex_nodes_id
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
Definition: triangle_mesh.template.h:1179
oomph::TriangleMesh::create_shared_boundaries
void create_shared_boundaries(OomphCommunicator *comm_pt, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, const Vector< FiniteElement * > &backed_up_f_el_pt, std::map< Data *, std::set< unsigned >> &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status)
Creates the shared boundaries.
Definition: triangle_mesh.template.cc:11538
is
respectively The red arrow identifies the reference point for the newly created node VI whose reference coordinate f IV and i e the nodes in its father element I w textwidth update_single Illustration of the default update procedure for the node update IV and V in its father element the default assignment is not appropriate for nodes that are updated by and the values of the coordinate at which the reference points are located This is illustrated in the sketch below in which the sub c parametrised by their coordinates f f are shown in magenta Note that the reference points for nodes II and IV are located in one sub c those for nodes III and V are located in another I w textwidth update_compound Illustration of the revised update procedure for the node update f at which the reference point with Lagrangian coordinate f it should be implemented in the function c described is appropriate If it is
Definition: fsi_collapsible_channel_adapt.txt:284
oomph::RefineableTriangleMesh::create_new_shared_boundaries
void create_new_shared_boundaries(std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< FiniteElement * >> &new_shared_boundary_element_pt, Vector< Vector< unsigned >> &new_shared_boundary_element_face_index)
Creates the new shared boundaries, this method is also in charge of computing the shared boundaries i...
Definition: triangle_mesh.template.cc:22702
oomph::RefineableTriangleMesh::construct_new_halo_node_helper
void construct_new_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new halo node (on an element) with the information sent from the h...
Definition: triangle_mesh.template.cc:19416
GeomObject
this is used if there is only a single node update as in the c AlgebraicCollapsibleChannelMesh n n A vector such as the intrinsic coordinates of reference points on the c GeomObjects n n By we assume that a newly created c AlgebraicNode is updated by the same node update function as the c AlgebraicNodes in its father element Therefore we pass the pointer to the c the node update function and the vector of pointers to c GeomObjects to the newly created c and interpolate the reference values between those stored at the c AlgebraicNodes in the father elements In most cases this provides a sensible default For it is hard to imagine a situation in which it would be sensible to update the position of newly created c AlgebraicNodes by a procedure that differs from that used for the surrounding c AlgebraicNodes that already existed in the father element since the reference values vary from node to in the c AlgebraicCollapsibleChannelMesh one of the reference values is the f x_1 f coordinate of the reference point on the fixed lower wall For the c AlgebraicNodes that already existed in the coarse base this value is given by the the c AlgebraicNodes f x_1 f coordinate in the undeformed mesh Interpolation of this value for the newly created c AlgebraicNodes results in an axially uniform subdivision of the refined elements The same procedure may be used to assign the reference value that represents the intrinsic coordinate of the reference point on the upper wall at least as long as the upper wall is only ever addressed as a compound c GeomObject
Definition: fsi_collapsible_channel_adapt.txt:226
oomph
Definition: annular_domain.h:34
oomph::RefineableTriangleMesh::get_required_elemental_information_load_balance_helper
void get_required_elemental_information_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * >> &f_haloed_ele_pt, FiniteElement *ele_pt)
Helper function to get the required elemental information from the element to be sent....
Definition: triangle_mesh.template.cc:26361
oomph::RefineableTriangleMesh::get_required_nodal_information_helper
void get_required_nodal_information_helper(unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from a haloed node so that a fully-functional h...
Definition: triangle_mesh.template.cc:18330
boundaries
mainpage Flow in a collapsible channel revisited enabling adaptivity in FSI problems In this document we re visit the collapsible channel problem yet again this time to demonstrate the use of spatial adaptivity in fluid structure interaction problems In such two additional issues have to be and then explain how these problems are addressed< HR >< HR > section history The assignment of positional history values for newly created nodes subsection what What is the problem We first discussed the use of spatial adaptivity for time dependent problems in the context of< A HREF="../../../unsteady_heat/two_d_unsteady_heat_adapt/html/index.html#spatial_adapt"> the unsteady heat equation</A > We showed that whenever a new node is c oomph lib s mesh adaptation procedures automatically assign the nodal values and history an initial assignment for the newly created c Node s current and previous in which case the newly created c Node s current position is determined by the father element s c MacroElement representation This ensures that the mesh refinement process respects curvilinear domain boundaries
Definition: fsi_collapsible_channel_adapt.txt:42
oomph::RefineableTriangleMesh::get_face_mesh_representation
void get_face_mesh_representation(TriangleMeshPolygon *polygon_pt, Vector< Mesh * > &face_mesh_pt)
Helper function to construct face mesh representation of all polylines, possibly with segments re-dis...
Definition: triangle_mesh.template.cc:35896
oomph::TriangleMeshParameters::element_area
double element_area() const
Helper function for getting the element area.
Definition: triangle_mesh.template.h:189
oomph::TriangleMesh::build_triangulateio
void build_triangulateio(const std::string &poly_file_name, TriangulateIO &triangulate_io, bool &use_attributes)
Helper function to create TriangulateIO object (return in triangulate_io) from the ....
Definition: triangle_mesh.template.cc:7197
oomph::classcomp::operator()
bool operator()(const std::pair< double, double > &lhs, const std::pair< double, double > &rhs) const
Definition: triangle_mesh.template.cc:15205
oomph::TriangleMesh::synchronize_boundary_coordinates
void synchronize_boundary_coordinates(const unsigned &b)
In charge of sinchronize the boundary coordinates for internal boundaries that were split as part of ...
Definition: triangle_mesh.template.cc:5610
oomph::TriangleMesh::set_mesh_level_time_stepper
void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Overload set_mesh_level_time_stepper so that the stored time stepper now corresponds to the new times...
Definition: triangle_mesh.template.h:897
oomph::TriangleMeshParameters::enable_use_attributes
void enable_use_attributes()
Helper function for enabling the use of attributes.
Definition: triangle_mesh.template.h:273
oomph::RefineableTriangleMesh::refine_triangulateio
void refine_triangulateio(TriangulateIO &triangulate_io, const Vector< double > &target_area, TriangulateIO &triangle_refine)
Build a new TriangulateIO object from previous TriangulateIO based on target area for each element.
Definition: triangle_mesh.template.cc:15054
oomph::RefineableTriangleMesh::create_element_load_balance_helper
void create_element_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * >> &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * >>> &received_old_haloed_element_pt, Vector< FiniteElement * > &new_elements_on_domain, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27501
oomph::RefineableTriangleMesh::update_shared_curve_after_restart
void update_shared_curve_after_restart(Vector< TriangleMeshPolyLine * > &vector_polyline_pt)
Updates the shared polylines representation after restart.
Definition: triangle_mesh.template.cc:43014
oomph::TriangleMesh::create_shared_polylines_connections
void create_shared_polylines_connections()
Establish the connections of the polylines previously marked as having connections....
Definition: triangle_mesh.template.cc:9511
oomph::AlgebraicCollapsibleChannelMesh::update_node_update
void update_node_update(AlgebraicNode *&node_pt)
Update the node-udate data after mesh adaptation. Empty – no update of node update required as this i...
Definition: collapsible_channel_mesh.template.h:567
oomph::TriangleMesh::shared_boundaries_ids
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
Definition: triangle_mesh.template.h:1455
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme_helper
void reset_halo_haloed_scheme_helper(Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, Vector< Vector< Node * >> &iproc_currently_created_nodes_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
In charge of creating additional halo(ed) elements on those processors that have no shared boundaries...
Definition: triangle_mesh.template.cc:17655
oomph::RefineableTriangleMesh::create_unsorted_face_mesh_representation
void create_unsorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt)
Helper function Creates an unsorted face mesh representation from the specified boundary id....
Definition: triangle_mesh.template.cc:35673
oomph::Bottom_left_sorter
struct oomph::classcomp Bottom_left_sorter
oomph::RefineableTriangleMesh::get_shared_boundary_elements_and_face_indexes
void get_shared_boundary_elements_and_face_indexes(const Vector< FiniteElement * > &first_element_pt, const Vector< FiniteElement * > &second_element_pt, Vector< FiniteElement * > &first_shared_boundary_element_pt, Vector< unsigned > &first_shared_boundary_element_face_index, Vector< FiniteElement * > &second_shared_boundary_element_pt, Vector< unsigned > &second_shared_boundary_element_face_index)
Use the first and second group of elements to find the intersection between them to get the shared bo...
Definition: triangle_mesh.template.cc:22550
oomph::RefineableTriangleMesh::unrefine_shared_boundary_constrained_by_target_area
bool unrefine_shared_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double >> &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40958
oomph::TriangleMesh::reset_boundary_element_info
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned >> &ntmp_boundary_elements_in_region, Vector< FiniteElement * > &deleted_elements)
Reset the boundary elements info. after load balance have taken place.
Definition: triangle_mesh.template.cc:14860
oomph::TriangleMesh::compute_holes_left_by_halo_elements_helper
void compute_holes_left_by_halo_elements_helper(Vector< Vector< double >> &output_holes_coordinates)
Compute the holes left by the halo elements, those adjacent to the shared boundaries.
Definition: triangle_mesh.template.cc:10819
oomph::TriangleMesh
Definition: triangle_mesh.template.h:423
oomph::classcomp
Definition: triangle_mesh.template.cc:15198
oomph::RefineableTriangleMesh::restore_boundary_connections
void restore_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the boundaries ...
Definition: triangle_mesh.template.cc:33175
oomph::TriangleMesh::get_halo_elements_on_all_procs
void get_halo_elements_on_all_procs(const unsigned &nproc, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, std::map< Data *, std::set< unsigned >> &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status, std::map< GeneralisedElement *, unsigned > &element_to_global_index, Vector< Vector< Vector< GeneralisedElement * >>> &output_halo_elements_pt)
Creates the halo elements on all processors Gets the halo elements on all processors,...
Definition: triangle_mesh.template.cc:11616
oomph::RefineableTriangleMesh::create_adjacency_matrix_new_shared_edges_helper
void create_adjacency_matrix_new_shared_edges_helper(Vector< Vector< FiniteElement * >> &unsorted_face_ele_pt, Vector< Vector< Node * >> &tmp_sorted_shared_node_pt, std::map< Node *, Vector< Vector< unsigned >>> &node_alias, Vector< Vector< Vector< unsigned >>> &adjacency_matrix)
Sort the nodes on the new shared boundaries (after load balancing), computes the alias of the nodes a...
Definition: triangle_mesh.template.cc:25845
oomph::RefineableTriangleMesh::construct_new_node_load_balance_helper
void construct_new_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * >> &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * >>> &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * >>>> &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned >>> &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new node (on an element) with the information sent from the load b...
Definition: triangle_mesh.template.cc:27905
oomph::TriangleMesh::read_distributed_info_for_restart
void read_distributed_info_for_restart(std::istream &restart_file)
Used to read info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7679
oomph::TriangleMesh::create_distributed_domain_representation
void create_distributed_domain_representation(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Creates the distributed domain representation. Joins the original boundaires, shared boundaries and c...
Definition: triangle_mesh.template.cc:8131
oomph::RefineableTriangleMesh::update_polygon_using_elements_area
bool update_polygon_using_elements_area(TriangleMeshPolygon *&polygon_pt, const Vector< double > &target_area)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:37662
oomph::RefineableTriangleMesh::get_connected_vertex_number_on_dst_boundary
bool get_connected_vertex_number_on_dst_boundary(Vector< double > &vertex_coordinates, const unsigned &dst_b_id, unsigned &vertex_number)
Computes the associated vertex number on the destination boundary.
Definition: triangle_mesh.template.cc:34092
oomph::RefineableTriangleMesh::add_vertices_for_non_deletion
void add_vertices_for_non_deletion()
Mark the vertices that are not allowed for deletion by the unrefienment/refinement polyline methods....
Definition: triangle_mesh.template.cc:31877
oomph::TriangleMesh::Point
Definition: triangle_mesh.template.h:2191
oomph::TriangleMesh::check_connections_of_polyline_nodes
const int check_connections_of_polyline_nodes(std::set< FiniteElement * > &element_in_processor_pt, const int &root_edge_bnd_id, std::map< std::pair< Node *, Node * >, bool > &overlapped_face, std::map< unsigned, std::map< Node *, bool >> &node_on_bnd_not_overlapped_by_shd_bnd, std::list< Node * > &current_polyline_nodes, std::map< unsigned, std::list< Node * >> &shared_bnd_id_to_sorted_list_node_pt, const unsigned &node_degree, Node *&new_node_pt, const bool called_from_load_balance=false)
Check for any possible connections that the array of sorted nodes have with any previous boundaries o...
Definition: triangle_mesh.template.cc:9071
s
respectively The red arrow identifies the reference point for the newly created node VI whose reference coordinate f IV and i e the nodes in its father element I w textwidth update_single Illustration of the default update procedure for the node update IV and V in its father element the default assignment is not appropriate for nodes that are updated by and the values of the coordinate at which the reference points are located This is illustrated in the sketch below in which the sub c parametrised by their coordinates f s
Definition: fsi_collapsible_channel_adapt.txt:254
oomph::RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper
void get_shared_boundary_segment_nodes_helper(const unsigned &shd_bnd_id, Vector< Vector< Node * >> &tmp_segment_nodes)
Get the nodes on the shared boundary (b), these are stored in the segment they belong.
Definition: triangle_mesh.template.cc:26031
oomph::TriangleMeshParameters::extra_holes_coordinates
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
Definition: triangle_mesh.template.h:201